Order of execution of back to back JavaScript Promises - javascript

In the following code:
new Promise((resolve, reject) => {
asyncFunc1(resolve,reject);
})
.then((result) => {
// do then1 stuff
})
new Promise((resolve, reject) => {
asyncFunc2(resolve,reject);
})
.then((result) => {
// do then2 stuff
})
Will asyncFunc1()'s .then() complete before asyncFunc2() is executed?
Or will both execute (nearly) simultaneously, and their then()s execute just whenever they happen to return?
If the second one does not wait for the first one, is there a way to make it do so other than moving asyncFunc2() into asyncFunc1()'s .then()?

Both promises will execute (nearly) simultaneously, because that is exactly one of the strengths of Javascript: Due to its callback-based design, it can kick off and wait for many asynchronous functions (in the form of promises) in parallel, without the need for the developer to care about complex handling of threads or anything like that.
If you want to have asyncFunc2 wait for the completion of asyncFunc1, it needs to be placed inside the then-block of asyncFunc1.
You can easily see and proof that by simulating two functions which take a defined time (using setTimeout), for example:
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved at ' + new Date().toISOString());
}, 2000);
});
}
function resolveAfter3Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved at ' + new Date().toISOString());
}, 3000);
});
}
function execPromises() {
console.log('calling at ' + new Date().toISOString());
resolveAfter2Seconds().then(result => console.log(result));
resolveAfter3Seconds().then(result => console.log(result));
}
execPromises();
You will see in the console output that the first one will finish 2 sec after starting the script, the other one 3 sec after starting the script (and not after 2 + 3 = 5 sec).
If you want to make asyncFunc2 wait for asyncFunc1 without the need for then, you can use the async/await keywords.
In my example, the function execPromises would then look like this (asyncFunc2 executed after completion of asyncFunc1!):
async function execPromises() {
console.log('calling at ' + new Date().toISOString());
const resultA = await resolveAfter2Seconds();
console.log(resultA);
const resultB = await resolveAfter3Seconds();
console.log(resultB);
}

Related

How does JavaScript call web APIs?

As far as I know, JavaScript's normal behavior when I call a web API just like the setTimeout 4 times:
it should call the first one then add it to a queue waiting for the call stack to be empty .. repeatedly it will do the same for all other apis .. so the second function should wait till the first executes then start to be called .. which means that it should take the second function 2 seconds or more, then it should take the third function three seconds or more ... and so on ...
what am I missing !?
Try to use async await and wait for each actions to be done.
const sleep = (ms) => new Promise(e => setTimeout(e, ms));
const logSeconds = async () => {
await sleep(1000);
console.log(new Date().toLocaleTimeString());
}
const main = async () => {
await logSeconds();
await logSeconds();
await logSeconds();
}
main()
var TimeOutOnTimeOut = () => {
setTimeout(() => {
console.log("Like this!");
TimeOutOnTimeOut();
}, 3000);
};
TimeOutOnTimeOut();
They'll all call at the same time, you could, however, call the next after the first is finished as described.

Meteor.call with await/promise doesn't seem to synchronous

I've been trying to call meteor.call in synchronous way. I tried to follow the example given in the meteor forum doesn't seem to work.
const callWithPromise = (method, myParameters) => {
return new Promise((resolve, reject) => {
Meteor.call(method, myParameters, (err, res) => {
if (err) reject('Something went wrong');
resolve(res);
});
});
}
The following function diiidn't wait for the above and doStuff() returned immediateley after call.
async function doStuff() {
const myValue1 = await callWithPromise('myMethod1', someParameters);
const myValue2 = await callWithPromise('myMethod2', myValue1);
}
Any Input in the above is appreciated.
Yes, await doesn't exactly do what you might expect (or want). And then it needs to be contained in an async function to be used :( It is still dealing with promises, and you need to be aware of that.
Meteor does, however, provide a Promise implementation that allows one to wait without needing to be inside an async function.
import { Promise } from 'meteor/promise'
and in your code you can do this:
const result = Promise.await(Metor.call('server-method',params))
result then contains whatever was returned by the Meteor method, so it behaves like a regular function call.
As Bergi already pointed out, even an async function will return right away -- as the name suggests! -- even if inside of it you are allowed to await things. So you'll need to await on the async function, too. Here is a simplified example:
const wait = () => { return new Promise((resolve, reject) => setTimeout(resolve, 2000)); }
async function doit() { await wait(); console.log('waited'); }
doit(); console.log('the end');
will result in:
the end
waited
however:
await doit(); console.log('the end');
will do what you seem to want, namely:
waited
the end

For loops, async await, promises - Javascript

I am trying to use a for loop to iterate through an array and perform an async function on each item. I want this to happen in a sequential order and I don't want the next async function for the next item in the array to execute until the async function for the previous item has COMPLETED.
I am using await and promises to try to do this. However, I must be doing something wrong because the code does not seem to be working right. The for loop only seems to work once.
Here is my code:
function asyncFunc(i)
{
//Here I am updating my database which is the async part of this function
return db.collection("collection").doc("doc").update({
})
.then(function(){
let d = new Date();
console.log(i + " async COMPLETED at: " + d.getTime());
return new Promise((resolve, reject) => {
resolve;
});
});
}
async function doWork()
{
var numbers = [1,2,3,4];
for(const i of numbers)
{
var d = new Date();
console.log(i + " async CALLED at: " + d.getTime());
await asyncFunc(i);
}
}
doWork();
Here is the console output:
1 async CALLED at: 1594683980009
1 async COMPLETED at: 1594683980280
Why is this happening?
So, you are returning two promises, which is a problem because you resolve one only to create a second which the main thread is then waiting on. All you have to do is return the promise that db.collection... gives you.
Fundamentally, the problem is that the new promise you create isn't resolved properly. You just say that the promise is (resolve, reject) => {resolve;} which is A) not even really a function and B) not going to resolve. Because you didn't call the resolve function. Truly though, this promise should never have been created because it was completely unnecessary, so I would worry more about just handling promises with simple awaits and returns than bothering with creating them. TL;DR Don't create a promise if there is already a promise that exists which you can use.
This code should work:
function asyncFunc(i)
{
//Here I am updating my database which is the async part of this function
return db.collection("collection").doc("doc").update({
})
.then(() =>{
let d = new Date();
console.log(i + " async COMPLETED at: " + d.getTime());
});
}
async function doWork()
{
var numbers = [1,2,3,4];
for(const i of numbers)
{
var d = new Date();
console.log(i + " async CALLED at: " + d.getTime());
await asyncFunc(i);
}
}
doWork();
For the sake of clarity regarding the actual issue you ran into, the problem is with this block of your code:
return new Promise((resolve, reject) => {
resolve;
});
The problem is that resolve needs to be a function that actually executes. Thus what you needed was this:
return new Promise((resolve, reject) => {
resolve();
});

Understanding NodeJs await with setTimeout() method

I'm fairly new to NodeJs and understanding the concept of async/await. Please correct me if I'm wrong - await keyword blocks the code until it gets a resolved value. For example:
const sampleFunction = async () => {
const result = await someAsynFunctionReturningPromise();
console.log('Log is printed here!');
}
In the above code, the compiler stops the code at 'const result = await someAsynFunctionReturningPromise();' until 'someAsynFunctionReturningPromise()' gets resolved, right?
With the above assumption, I tried the below setTimeout() code:
const sampleFunction = async () => {
const result = await setTimeout(()=>{
console.log('This is printed after 2 seconds');
},2000);
console.log('Log is printed here!');
}
However, the above code doesnt await till setTimeout() is resolved, it skips to the next line, printing 'Log is printed here!'.
Can anyone please help me understand if my understanding is wrong?
In order for await to work with setTimeout, setTimeout needs to return a promise. Please see this: How to make a promise from setTimeout
This is where the event loop of node JS working comes in. In the first place your
someAsynFunctionReturningPromise()
is returning a promise where in the second code setTimeout() does not return you promise. Also when nodejs eventloop gets such a function like setTimeout() it will put it in callstack and then to taskqueue where it will wait for 2000ms and goes for the next line of execution, that is why it is printing
console.log('Log is printed here!');
when 2000ms are over the setTimeout will be kept from taskqueue to callstack and it will execute
console.log('This is printed after 2 seconds');
You wrote your own answer. You wrote
await keyword blocks the code until it gets a resolved value
In your code you never resolved anything so of course it won't work
A setTimeout that resolves is
function wait(ms = 0) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
};
}
or the terse version
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
Example
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const sampleFunction = async () => {
for(;;) {
await wait(2000);
console.log('time since page loaded:', performance.now() / 1000 | 0);
}
};
sampleFunction();

How do I know which promise will resolve first?

I have a snippet that I'm playing around with where I've purposely placed Promise.resolve(c) before Promise.resolve(a) but I am noticing that the true value from bottom Promise.all(...) is being logged first.
const https = require('https');
function getData(substr) {
let url = ``;
return new Promise((resolve, reject) => {
try {
https.get(url, res => {
let s = '';
res.on('data', (d) => {
s += d
});
res.on('end', () => {
let data = JSON.parse(s);
resolve(data);
})
})
} catch (e) {
reject(e);
}
})
}
let a = getData('spiderman');
let b;
let c = getData('superman');
Promise.resolve(c)
.then(value => console.log(value));
Promise.resolve(a)
.then(value => b = value);
Promise.all([a]).then(values => console.log(values[0] === b));
Is there any explanation as to why this is the case? I would think that since Promise.resolve(c) comes first, that the Promise c would resolve first and be logged. Or is there no way to actually rely on the order of the logs aside from using callbacks? What are the best practices to avoid such issues?
These are asynchronous calls that on complete resolve using the supplied function passed into then.
There is no way to force one of these to finish before and if you need that you should be running these synchronous.
When you call .then() this only gets called when the function finished not when the .resolve gets called.
Promise resolution order is not guaranteed. That's kinda the point of asynchronous code.
If you rely on order of execution, you should be using synchronous code.
Use Promise.all() with both requests if you want them both completed before you do your next step.
let a = getData('spiderman');
let c = getData('superman');
Promise.all([a, c]).then(([spidyResults, superResults]) => {
// both have sompleted
// do stuff with each set of results
}).catch(err => console.log('Ooops, one of them failed') );
Well, as said before, the order of the promise completion is not guaranteed, because it's an async operation.
If you really need the execution to follow a certain order you need to put the the next thing to be executed inside then or use async and await which is much cleaner.

Categories

Resources