ionic Async-await not working - angularjs

my code is:
async getDetails(){
for(var i=0;i<this.results.length;i++){
// this.booking.length=0;
// this.hbl.length=0;
var hblList=[];
var bookingList=[];
await this.api.get("track/dtl",
{
loadPortId: this.results[i].loadPortId,
dischargeId:this.results[i].dischargeId,
scheduleId: this.results[i].scheduleId
})
.subscribe(res1 => {
//let resp1 = res1;
this.details= res1;
bookingList.length=0;
hblList.length=0;
for(var j=0;j<this.details.length;j++){
if(this.details[j].bookNo!== undefined){
bookingList.push(this.details[j]);
}else if(this.details[j].hblNo!== undefined){
hblList.push(this.details[j]);
}
}
// this.results[i]["hbl"]=this.hbl;
// this.results[i]["booking"]=this.booking;
console.log("this.hbl inside subscribe::::::::::::"+hblList);
console.log("this.booking inside subscribe::::::::::::"+bookingList);
console.log("this.results[i] after::::::::::::"+this.results[i]);
});
this.results[i]["hbl"]=hblList;
this.results[i]["booking"]=bookingList;
console.log("this.hbl after::::::::::::"+hblList);
console.log("this.booking after::::::::::::"+bookingList);
console.log("this.results[i] after::::::::::::"+this.results[i]);
this.getCurrent(this.results[i].queries[0]);
}
}
I want to make async call for each for loop item. could anyone please help me to use async-await to make sure the first and every async call is completed prior to the next call.
Thanks in advance

As you are subscribing in the Observable you're not using the async/await approach. Async/await works only with Promises, so, you need to transform your observable to promise first.
I don't know how your this.api works, but, maybe, you should have a toPromise() function. Using await you won't need to subscribe or to use ".then()" promise function.

I have no means of trying your code or trying mine, but here, take a look at this one that should work in theory.
The main point is: you have to decide whether to use Observables or to use Promises. Unfortunately the Angular team decided to return Observables in their http module. Observables do not work with async await, but there is a simple conversion: Observable.prototype.toPromise(). Use that, and get rid of .subscribe.
async getDetails(){
for(var i=0;i<this.results.length;i++){
// this.booking.length=0;
// this.hbl.length=0;
var hblList=[];
var bookingList=[];
var res1 = await this.api.get("track/dtl", {
loadPortId: this.results[i].loadPortId,
dischargeId:this.results[i].dischargeId,
scheduleId: this.results[i].scheduleId
}).toPromise();
this.details= res1;
bookingList.length=0;
hblList.length=0;
for(var j=0;j<this.details.length;j++){
if(this.details[j].bookNo!== undefined){
bookingList.push(this.details[j]);
} else if(this.details[j].hblNo!== undefined){
hblList.push(this.details[j]);
}
}
this.results[i]["hbl"] = hblList;
this.results[i]["booking"] = bookingList;
console.log("this.hbl after::::::::::::"+hblList);
console.log("this.booking after::::::::::::"+bookingList);
console.log("this.results[i] after::::::::::::"+this.results[i]);
this.getCurrent(this.results[i].queries[0]);
}
}

Related

web3.js how can i save value in variable from function?

I am trying to get started with web3.js. There are two different examples for getBlockNumber or getBalance:
web3.eth.getBlockNumber(function (error, result) {
console.log(result);
});
or shorter
web3.eth.getBlockNumber()
.then(console.log);
But how do I save the output to process it further? No matter how I try, I only get "Promise { }".
I have read many posts on this but have not found a solution that works for me.
let result;
const blockNumber = async () => {
result = await web3.eth.getBlockNumber();
};
blockNumber();
Let me know if that solve your problem. Actually "everything" it's a promise in web3 that's why you need async/await
^ console.log the result variable ofc.

React: Method finishing before data loaded

I am trying to retrieve some data from Yahoo Finance using an XHTML Request, which works. However, I am trying to display the data retrieved on my app, but the method to retrieve the data is returning "undefined" before the data has been loaded.
async componentDidMount() {
var tempData = await this.fetchAsync();
console.log(tempData)
this.handleLoad(tempData)
}
handleLoad = (num) => {
this.setState(state => ({
price: num
}));
}
async fetchAsync () {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
const {params} = this.props.navigation.state;
var ticker = params.ticker;
var result;
var tempArray = [1];
var url = "https://yahoo-finance-low-latency.p.rapidapi.com/v8/finance/spark?symbols=" + ticker + "&range=2y&interval=1d"
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
result = JSON.parse(this.responseText);
tempArray = result[ticker]['close'];
testPrice = tempArray[tempArray.length-1]
console.log(testPrice)
var self = this;
return tempArray[tempArray.length-1]
}
});
xhr.open('get', url, true);
xhr.setRequestHeader("x-rapidapi-key", "my key");
xhr.setRequestHeader("x-rapidapi-host", "yahoo-finance-low-latency.p.rapidapi.com");
xhr.send();
}
I am using the componentDidMount() function to begin calling the methods to load the data, but when the app renders, the values are not displayed.
As you can see inside the fetchAsync() method, I return the value I need, but when I try and console.log the return from this method, I get undefined.
I have also tried moving this return to the end of the method, but when I use console.log here to ensure that tempArray has the data I need, it is empty.
I need to display tempArray[tempArray.length-1] on my screen, but the data is not loaded in time, and does not update even after it has loaded.
Your return tempArray[tempArray.length-1] inside the fetchAsync isn't actually returning from fetchAsync -- it's just returning from the callback function inside addEventListener. In fact, you don't actually have any code that is taking advantage of the async tag you have on that function.
One solution to this would be to call handleLoad directly from inside fetchAsync instead of return tempArray. (Of course, you'll want to make sure that you've bound this correctly to handleLoad).
Another solution would be to pass a callback function into fetchAsync that you could call instead of returning. Then, at your call site, it might look something like this:
this.fetchAsync((tempData) => {
console.log(tempData)
this.handleLoad(tempData)
});
Finally, a third solution would be to switch from XMLHTTPRequest to fetch, and then you could take advantage of async/await and actually make that fetchAsync method async (and be able to return a value from it).

How to wait for getDownloadURL to finish in my mapping function before updating my object array in react state?

getImages() {
const entries_copy = this.state.entries;
entries_copy.map(entry => {
storage.refFromURL(entry.sign_in_photo).getDownloadURL()
.then((url) => {
entry["inPhotoURL"] = url;
storage.refFromURL(entry.sign_out_photo).getDownloadURL()
.then((url) => {
entry["outPhotoURL"] = url;
});
}).catch((error) => {
// Handle any errors
});
});
this.setState({entries: entries_copy});
}
I'm trying to retrieve the download url for images and store them in my entry object inside my entries object array but the problem I'm facing right now is that the setState is called before the urls are retrieved and I have no idea how to wait for it to complete before setting the state. I have searched for similar problems but most of them are solved by executing it inside then() but for mine, I can't execute it inside then() because I have to wait for all the entries to be updated. I have only recently started using React for this project so I'm sorry if the answer is obvious.
This is because the code in asynchronous.
You should call setState inside the .then() function.
I would recommend you to read about Promises in Javascript. They are an important aspect of the language to master.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
In addition to the answer of #TomSlutsky, note that you need to correctly chain your promises and you should not forget to "always return results, otherwise callbacks won't catch the result of a previous promise".
So you need to do as follows:
storage.refFromURL(entry.sign_in_photo).getDownloadURL()
.then((url) => {
entry["inPhotoURL"] = url;
return storage.refFromURL(entry.sign_out_photo).getDownloadURL()
})
.then((url) => {
entry["outPhotoURL"] = url;
this.setState(...);
})
.catch((error) => {
// Handle any errors
});
Note also how the catch() method is called at the end of the chain, see the doc for more details (and possible other options).

Node.js beginner struggling with arrays, promises and Async

A node.js (and coding in general) beginner here, struggling with the async nature of node. I'm trying to write some code that will look up the members of certain AD groups and add the member names to an array, as per the "getMembers" function below. I'm only interested in computer objects, which is why I only have ad.find returning "other" objects.
Once that is complete, I want the "processAssets" function to do something with the array - for the purpose of testing, just ouptutting to the console.log. The problem is that "processAssets" is running before "getMembers" has populated the array. What am I doing wrong? I realise the answer may begin with "several things"...!
const ActiveDirectory = require('activedirectory');
var ad = new ActiveDirectory(config);
var query = 'memberOf=cn=';
var cNames = [
'group1',
'group2',
'group3'
];
var baseOu = ',ou=Groups,dc=example,dc=com';
function run(cNames) {
Promise.all(cNames.map(cName => getMembers(cName))).then(processAssets())
}
async function getMembers(cName) {
await ad.find(query + cName + baseOu, async function(err, results) {
if ((err) || (! results)) {return;}
await _.each(results.other, function(other) {
assetArray.push(other.cn);
});
});
}
function processAssets() {
console.log("Contents of assetArray (" + assetArray.length + " assets):");
assetArray.forEach(function(item) {
console.log(item);
});
}
thanks in advance.
You have some things mixed up.
The main problem causing your immediate issue is this line:
Promise.all(cNames.map(cName => getMembers(cName))).then(processAssets())
You need to pass a function to then() which will be called when the promise resolves. You are not doing that, you are passing it the result of calling processAssets(), which has the effect of calling processAssets() immediately. Typically you would us something like:
Promise.all(cNames.map(cName => getMembers(cName))).then(() => processAssets())
/* ^^ pass a function */
Additionally you are await things for no purpose. There's no reason to await here:
await ad.find(query + cName + baseOu, async function(err, results) {
ad.find doesn't return a promise. In general functions that take callbacks don't return promises (maybe there are some exceptions, but I can't think of any). If you want to have a promise to use in run()'s Promise.all you need to wrap the find function in a promise and return it. Something like:
function getMembers(cName) {
return new Promise((resolve, reject) => {
ad.find(query + cName + baseOu, function(err, results) {
if (err) return reject(err)
// I'm making some assumptions about results. But hopefully this gives
// a good enough idea
let data = results.other.map(other => other.cn)
resolve(data)
});
});
}
Now getMembers returns a promise that resolves to the result of ad.find and you can use it in `Promise.all.

Multiple $http calls doesn't return in the right order

I made a for loop and inside I make a $http call to my API.
The for loop makes the calls in a specific order, but how I get the reponse is totally messed up..
This is my code:
for (var i = 0; i < amountOfEntries; i++) {
var _imageId = NieuwsService.nieuws[i].image;
if (_imageId != "") {
var uriString = "Web/Lists/getbytitle('Afbeeldingen%20voor%20nieuwsberichten')/Items(" + _imageId + ")/File";
NieuwsService.createRequest(requestUrl, baseUrl, uriString).then(function (response) {
var _parser = new DOMParser();
var _xmlData = _parser.parseFromString(response.data, "text/xml");
var _entry = _xmlData.getElementsByTagName("entry");
var _imageUrl = "http://sharepoint" + _entry[0].getElementsByTagNameNS("*", "ServerRelativeUrl")[0].childNodes[0].nodeValue;
//Display
$('#imageList').append("<li><a href='#'>" + _imageUrl + "</a></li>");
NieuwsService.images.push(_imageUrl);
})
}
}
var _createRequest = function (requestUrl, baseUrl, uriString) {
var promise = $http.get(requestUrl, {
params: {
"baseUrl": baseUrl,
"uriString": uriString
}
})
return promise;
}
NieuwsService.createRequest = _createRequest;
return NieuwsService;
So the question is, how do I get the responses in the order I make the calls?
You can create and array of promises, then use $q.all that will resolve when all the requests are done, and you will have the result of each one in the same position where you added the promise.
$http is ASYNC by design, it means that each HTTP will go out in the same order but the response depends on many cases (network,dns, server response time ext...)
you should design your code in a way that it will take that into consideration.
You can use promise
As #RonnieTroj pointed out, the ajax calls are asynchronous and there is no defined order in that respect.
However, if you want to chain api calls such that you get responses in a specific order, then your only option is nesting calls in the following way:
call1.then(function(data1) { //first call
call2.then(function(data2) {//second call after first call completes
//and so on
})
})
However, the issue with this method is that it will take more time because you are essentially making the calls sequential in nature(one call executes, then another instead of parallel async calls.)

Resources