Reputation: 1179
I'm trying to make a call to a service and build an object with the resulting value. If I knew what I was doing, I'd also handle errors, but I don't know how. Unfortunately, the code begins the service call, then returns to the statement following the service before the service call finishes.
I don't care how un-modern, un-cool or whatever it is, I want this code to wait for the service to succeed or fail. Everything I do in the app depends on this service succeeding anyway.
I both tried setting breakpoints and as adding logging statements.
import { Injectable, Injector } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { UUID } from 'angular2-uuid';
import { Constants } from './constants';
@Injectable()
export class AppConfigService {
private constants = null;
constructor (private injector: Injector) { }
loadAppConfig() {
let http = this.injector.get(HttpClient);
/*
return http.get('/assets/app-config.json')
.toPromise()
.then(data => {
this.appConfig = data;
})
*/
if(this.constants != null) {
console.log('@@WOODSMAN environmentData is not null');
console.log('@@WOODSMAN lazy loaded environmentData already is '+JSON.stringify(this.constants));
} else {
console.log('@@WOODSMAN environmentData is null');
let headerValues = new HttpHeaders()
.set('Accept-Encoding', 'application/json; charset=UTF-8')
.set('Content-Type', 'application/json; charset=UTF-8')
.set('SC_TRACE_ID', UUID.UUID());
let httpOptions = {
headers: headerValues
};
console.log('@@WOODSMAN: Waiting for environment info from service call');
let appConfig = http.post("/proxy/report/getEnvironment", "",httpOptions)
.toPromise().then(data => {
this.setConstants(data);
});
/*
while(this.environmentData == null) {
console.log('@@@WOODSMAN appConfig is null even after service call');
}
*/
if(this.constants == null) {
console.log('@@@WOODSMAN appConfig is null even after service call');
}
};
console.log('@@WOODSMAN: environmentData result = '+JSON.stringify(this.constants));
}
private setConstants(environmentData) {
console.log('@@WOODSMAN calling environmentData='+JSON.stringify(environmentData));
this.constants = new (environmentData);
}
get config() {
//return this.appConfig;
if(this.constants==null) {
console.log('@@WOODSMAN Call to config found null appConfig. Calling the load');
this.loadAppConfig();
if(this.constants==null) {
console.log('@@WOODSMAN Second call to config still found null appConfig.');
}
}
console.log('@@WOODSMAN environment.salesconnectURL' + this.constants["baseUrl"]);
console.log('@@WOODSMAN environment.salesconnectURL' + this.constants["homepageURL"]);
console.log('@@@WOODSMAN end getConstants ');
return this.constants;
}
}
I see in the browser log these two lines in this order (with no log statements between them). '@@WOODSMAN: Waiting for environment info from service call' '@@@WOODSMAN appConfig is null even after service call'
I tried wrapping this in an async function and adding an await statement, but it still ignored that and did not wait for completion.
Since the service takes milliseconds to complete, I tried adding a while loop above to wait until the value got set. However, it became a forever loop as the service handler was not allowed to satisfy the loop condition.
*** Update
I tried adding a query call which offers a synchronous capability. So I coded the following:
let ajaxObject = {
type: "POST"
,headers: {
'Accept-Encoding' : 'application/json; charset=UTF-8'
,'Content-Type' : 'application/json; charset=UTF-8'
,'SC_TRACE_ID' : UUID.UUID()
}
,url: "/proxy/report/getEnvironment"
,async : false
,data: ""
,success: function(data) {
this.status="SUCCESS";
this.dataReturned = data;
console.log('@@WOODSMAN success reached');
}
,error: function(jqXHR, textStatus, errorThrown) {
this.status="FAILURE";
this.jqXHR = jqXHR;
this.textStatus = textStatus;
this.errorThrown = errorThrown;
console.log('@@WOODSMAN failure reached');
console.log('Error on call to getEnvironment. '+textStatus+' '+errorThrown);
}
,status: "NOT_RUN"
,dataReturned : null
,jqXHR: {}
,textStatus: {}
,errorThrown: {}
};
$.ajax(ajaxObject);
console.log('@@@WOODSMAN after ajax service call' + JSON.stringify(ajaxObject));
When I run this, I get '@@@WOODSMAN after ajax service call' with the status being 'NOT_RUN'; This means that at the point the call is made, it did not execute either the success or the failure functions. Note that the request had async: false, set, so it has no excuse for doing an asynchronous call.
Is it possible to do socket programming in Javascript? It's becoming apparent that making a synchronous call is incredibly difficult anymore.
Upvotes: 1
Views: 58
Reputation: 5194
You should know that JS is Asynchronous , Means any code that deals with WEB API , It wont't wait for it to get complete , instead it will keep executing the next line of codes.
In the snippet shared by You , the lines
let appConfig = http.post("/proxy/report/getEnvironment", "",httpOptions)
.toPromise().then(data => {
this.setConstants(data);
});
is asynchronous. Hence JS engine won't wait for it to get complete and it will execute the next line of code . that is :
if(this.constants == null) {
console.log('@@@WOODSMAN appConfig is null even after service call');
}
Since above lines gets executed before the service call is finished, the value of
this.constants
is null
that time . This is the reason you are able to see the last statement in the console.
To check Whether this.constants
is null
even after the service call , you can modify the code as below :
let appConfig = http.post("/proxy/report/getEnvironment", "",httpOptions)
.toPromise().then(data => {
this.setConstants(data);
if(this.constants == null) {
console.log('@@@WOODSMAN appConfig is null even after service call');
}
});
** update. :
this is the way you should implement async-await
. :
public async loadAppConfig() {
let http = this.injector.get(HttpClient);
let appConfig = await http.post("url",{options})
.toPromise().then(data => {
.... next lines
});
console.log('this line will not execute until await is finished');
}
Here is the stackblitz demo. : demo
Upvotes: 2