Promise resolve confusion - javascript

When I resolve the promise, the function should continue being executed:
function test(){
return new Promise(resolve=>{
resolve(5)
setTimeout(()=>{console.log(7)}, 2000}
})
}
And then I invoke the function like this
test().then(console.log);
So it prints 5, and then after 2 seconds, it prints 7, as I expected.
But if I work with sync thing after resolve() it works differently:
function test(){
return new Promise(resolve=>{
resolve(5)
for(let i = 0; i < 100; i++)
console.log(i)
})
}
Now it prints the numbers from 0 to 100, and then it prints 5. But I expected it to return 5 through resolve() and only then print all the rest stuff.

The code gives the expected outcome. When you resolve immediately with 5, the function isn't finished executing yet, so it runs the rest of the code. Once done, the call stack is empty and the asynchronous then gets its chance to run. The difference between the two programs is that the second one logs immediately because it does not have to wait for the function to finish to execute. It's synchronous.

I think it has to do with javascript's event loop. With the link you can watch amazing video about event loop in JS.
I'm not sure, but it seems like what's inside resolve() is called asynchronously, but for loop is sync, that's why what's inside resolve is put into a queue and for loop is executed immediately. After "normal" execution process finished, resolve does it's job, returning 5.
In the example with setTimeout you've put the code into queue, but for later(2000ms) execution. Since 5 doesn't do anything, it's returned right away(asynchronously though) and after 2 seconds your code is run. Wath the video.

I figured it out.
Nodejs runs code from left to right.
First it gives me a function with resolve reject as arguments, then it executes this function. It resolves the value. Then it encounters a synchronous for loop, therefore it has to execute it synced. Then it returns an already resolved promise that I apply method then on. then() executes the callback when the promise is resolved. It is already resolved. And it prints my resolved value
If you use callbacks it will be different:
function test(callback){
callback(7)
for(let i = 0; i<100; i++){
console.log(i)
}
}
it will first, print(7) and only then all the rest numbers
But it works only if you know that the callback will be invoked once. Because otherwise, it will break the logic.

So, a few things I wanted to make sure we're on the same page. Your test function's setTimeout is asynchronous. Yes, it's inside a promise, but you've sent it to the event loop in an uncontrolled manner.
setTimeout(()=>{console.log(7)}, 2000} //not controlled in your first function
Whatever you place in resolve is the only thing that gets controlled by the promise. The way you're using the promise is not how they are supposed to be used. You might have to go back to basics and read up on it some more if this confuses you.
edit: I seemed to have no articulated myself properly, and thus have garnered quite a bit of salt. Better explanation:
You should treat a promise how you would a return statement. A promise function should not perform any other output operation except a single resolve statement. This can then be synchronously controlled in subsequent operations in another function. Key word is another.
function test(){
return new Promise(resolve=>{
resolve(5)
})
}
function loopTest() {
test().then( (num) => {
console.log(num)
for (let i = 0; i < 10; i++) {
console.log(i)
}
})
} // what you were trying to actually accomplish
loopTest()

Related

event emitter emit in sequence or in parallel, and behaviour when they are async

Consider the following code:
import events from 'events';
const eventEmitter = new events.EventEmitter();
eventEmitter.on('flush', (arg)=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
}
})
setTimeout(()=>{
eventEmitter.emit('flush', `Fourth event`);
}, 5000);
setTimeout(()=>{
eventEmitter.emit('flush', `Third event`);
}, 4000);
setTimeout(()=>{
eventEmitter.emit('flush', `First event`);
}, 2000);
setTimeout(()=>{
eventEmitter.emit('flush', `Second event`);
}, 3000);
Output1:
1 First event
2 First event
3 First event
.
.
.
1 Second event
2 Second event
3 Second event
.
.
.
1 Third event
2 Third event
3 Third event
.
.
.
1 Fourth event
2 Fourth event
3 Fourth event
What I wanted to know was, does the event that is emitted get completed first then only the second event get emitted? Or can I expect something like this:
Output2:
1 First event
1 Second event
2 Third event
3 Fourth event
3 Third event
.
.
.
What if I wrote the emitter.on function like this:
eventEmitter.on('flush', (arg)=>{
const mFunc = async ()=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
}
}
mFunc();
})
I was expecting output like Output2, but, instead I got something similar to Output1. Could someone please explain me this behaviour?
Also, consider this case:
eventEmitter.on('flush', (arg)=>{
const mFunc = async ()=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
await updateValueInDatabase(i);
}
}
mFunc();
})
Now, what would be the behaviour of the function?
Coalescing my comments into an answer and adding more commentary and explanation...
Emitting an event from an EventEmitter is 100% synchronous code. It does not go through the event loop. So, once you call .emit(), those event handlers will run until they are done before any other system events (e.g. your timers) can run.
Calling an async function is NO different from the calling point of view at all than calling a non-async function. It doesn't change anything. Now, inside an async function, you could use await and that would cause it to suspend execution and immediately return a promise, but without await, making a function async just makes it return a promise, but doesn't change anything else. So, calling the async version of mFunc() is exactly the same as if it wasn't async (except it returns a promise which you don't use). Doesn't changing sequencing of events at all.
Since you apparently thought it would change things, I'd really suggest reading a bunch more about what an async function is because your perception of what it does is apparently different than what it actually does. All async functions return a promise and catch internal exceptions which they turn into a rejected promise. If you don't use await, they just run synchronously like everything else and then return a promise.
Calling an async function returns ONLY when you hit an await or when the function finishes executing and hits a return or the implicit return at the end of the function. If there's no await, it just runs like a normal function and then returns a promise (which you aren't doing anything with). As I said above, you really need to read more about what async functions actually are. Your current understanding is apparently incorrect.
Here are some summary characteristics of an async function:
They always return a promise.
That promise is resolved with whatever value the function eventually returns with a return statement or resolved with undefined if no return statement.
They run synchronously until they either hit a return statement or an await.
At the point they hit an await, they immediately return a promise and further execution of the function is suspended until the promise that await is on is resolved.
When they suspend and return a promise, the caller receives that promise and keeps executing. The caller is not suspended unless the caller also does an await on that promise.
They also catch any synchronous exceptions or other exceptions that aren't themselves in an asynchronous callback and turn those exceptions into a rejected promise so the promise that the async function returns will be rejected with the exception as the reason.
So, if there is no await in an async function, they just run synchronously and return a promise.
In your last version of code, if you end up making your event emitter handler actually be asynchronous and actually await long enough for other things to get some cycles, then you can create some competition between timers and promises waiting to notify their listeners. The promises waiting to notify their listeners will get to run before the timers. That makes your situation of mixing those two types very complicated and very dependent upon timings. A non-ending sequence of promises waiting to notify their listeners can make timers wait until there are no more promises waiting to notify. But, if there's a moment with no promises waiting to notify, then your next timer will fire and will kick off it's own set of promise-driven operations and then all the promise-driven operations will likely interleave.
Also, emitter.emit() is not promise-aware. It doesn't pay any attention to the return value from the callbacks that are listening for the emit. So, it doesn't make any difference at all to emitter.emit() whether the listeners are async or not. As soon as they return (whether they returned a promise or not), it just goes right on to whatever it was going to do next. Promises only influence code flow if the recipient uses them with await or .then() and .catch(). In this case, the recipient does nothing with the return value so emitter.emit() just goes right onto its next order of business and executes that.
okay, so, if I have a bunch of async function arrays [async1, async2, async3, ....], and they all have await statements internally, what would be the best way to execute them in sequential order? i.e. one after other in order of their index?
Well, if you had an array of async functions that properly resolve their promise when they are actually done with their work, you can execute them sequentially by just looping through the array with an await.
async function someFunc() {
const jobs = [asyncFn1, asyncFn2, asyncFn3];
for (let job of jobs) {
let result = await job(...);
}
}
Internally, the EvenEmitter hold an array of listeners for each event type. When you emit an event type, the EvenEmitter just goes through it's array of listeners and execute it. Therefore, the listeners are executed in the order it was added by addListener or on method.
To answer your questions there are two parts: a) it executes in the order you added the listener and b) it depends if the listeners are async or not. If your listeners are synchronous, then you can expect that behavior. If your listeners are async, you can't expect that. Even if your execute your async synchronously, they will not necessarily resolve at the same time because it's the nature of being async.

How do I update the values of objects outside of a function? [duplicate]

Why does a function called after my promise execute before the promise's callback?
I read this in MDN, but didn't understand it
"Callbacks will never be called before the completion of the current
run of the JavaScript event loop."
I thought it meant that if I have any other statements after resolve() or reject() they will get executed before the callback is invoked. Though, that seems to be an incomplete understanding.
function myFunction() {
return new Promise( function(resolve, reject) {
const err = false;
if(err) {
reject("Something went wrong!!!");
}
else {
resolve("All good");
}
});
}
myFunction().then(doSuccess).catch(doError);
doOther();
function doError(err) {
console.log(err);
}
function doSuccess() {
console.log('Success');
}
function doOther() {
console.log("My Other Function");
}
Output:
My Other Function
Success
By specification, a promise .then() or .catch() callback is never called synchronously, but is called on a future tick of the event loop. That means that the rest of your synchronous code always runs before any .then() handler is called.
So, thus your doOther() function runs before either doSuccess() or doError() are called.
Promises are designed this way so that a promise .then() handler will be called with consistent timing whether the promise is resolved immediately or resolved some time in the future. If synchronous .then() handlers were allowed, then calling code would either have to know when it might get called synchronously or you'd be susceptible to weird timing bugs.
In the Promises/A+ specification which the promises in the ES6 specification were based on, it defines a `.then() handler like this:
promise.then(onFulfilled, onRejected)
and then has this to say about it:
2.2.4. onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
And, then it defines platform code like this:
Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
Basically what this means is that .then() handlers are called by inserting a task in the event loop that will not execute until the currently running Javascript finishes and returns control back to the interpreter (where it can retrieve the next event). So, thus any synchronous Javascript code you have after the .then() handler is installed will always run before the .then() handler is called.
I had similar confusions about what it means by executing after the current loop. I was going through MDN docs on Promises, which says the following:
Callbacks added with then() will never be invoked before the completion of the current run of the JavaScript event loop.
This website http://latentflip.com/loupe/ video expains it pretty well, basically api's like setTimeout execute after the inbuilt js functions. But, the problem with callbacks is, if it doesn't use those apis then it might execute before the finish of current run of the event loop. Following examples show the difference:
Old school callbacks
var foo = function(then1) {
console.log("initial");
var i = 0;
while (i < 1000000000) {
i++;
}
then1();
}
function then11() {
console.log("res");
}
foo(then11);
console.log("end"); // unlike Promises, end is printed last
New Promise
var promise = new Promise(function(resolve, reject) {
console.log("Initial");
//while loop to 10000
var i = 0;
while(i<1000000000) { //long async task without ext apis
i++;
}
resolve("res");
});
promise.then(function(result) {
console.log(result); // "Stuff worked!"
});
console.log("end"); // end is printed before res!!!

Why are my promises not processing asynchronously?

I have two functions, one function, asyncTest_returnPromise simply returns a promise, and another function, asyncTest, calls that promise 3 times by calling Promise.all(promises) on an array of promises. Within each promise in the array, I send one value ("Foo") to the console before the asyncTest_returnPromise function is called, and send another value ("Bar") to the console after it is called.
Given my understanding of the Promise.all function, I would have expected each promise within the array to be processed only after the subsequent promise had been fulfilled, meaning that as both console.log statements are within each promise in the array, the result would have been:
Foo
Bar
Foo
Bar
Foo
Bar
Instead, however, the output seems to be:
Foo
Foo
Foo
Bar
Bar
Bar
As all instances of "Foo" have been sent to the console before even the first "Bar", it seems to me these promises must be being processed concurrently.
Here are the two functions:
function asyncTest_returnPromise() {
return new Promise((resolve, reject) => {
resolve()
})
}
function asyncTest() {
var promises = []
for (i = 0; i < 3; i++) {
promises.push(new Promise((resolve, reject) => {
console.log("Foo")
asyncTest_returnPromise().then(_ => {
console.log("Bar")
resolve();
})
}))
}
Promise.all(promises)
}
asyncTest();
So I would like to know, have I misunderstood the purpose of Promise.all or how it works? Has some other part of my code caused all "foo" outputs before all the "bar" outputs? Is there something I need to do to have the entirety of each promise complete before moving on to the next one?
They are running asynchronously.
Each time around the loop you:
Log Foo
Create a promise (which resolves immediately)
Use then to queue up a function to run after the promise resolves
Then the loop goes around for the next iteration.
Afterwards, when the asyncTest function is finished , the event loop is free to look at the queued up functions.
Since all the promises are resolved, they each run (and log Bar).
If you want to wait for a promise before going around the loop again, then you should look at the await keyword which would let asyncTest pause (and go to sleep) until a promise resolved.
It's just how Event Loop works. Let me explain how it's processed in simple words:
First, the loop starts and runs 3 times. Each time it creates a new microtask and puts it in the microtask queue for later handling. The order in which those microtasks have been created is kept.
Now those microtasks are being handled one at a time, synchronously. Each of those microtasks (which are run synchronously as the Loop runs) executes console.log('Foo'); and then creates another microtask (another Promise) which are queued by the .then() call. So this additional microtask is put into the queue (behind those three first microtasks). It happens for every microtask created by the loop (so it's 3 times). This is where you have Foo printed 3 times.
Now that all our microtasks (3) have been processed, the Event Loop keeps going and takes the next microtasks for processing. This time it's a microtask that runs console.log('Bar');. It happens also three times. Here's where you get Bar printed 3 times.
Of course, there's more that happens in the Event Loop but this is essentially what happens with your Promises here.

Promise async call

I am new to node js and trying to understand how to make async calls.
I am trying to wrap a function into a promise in order to make it async. For simplicity, the function is just a loop that takes time :
var p = new Promise(resolve => {
for (let i=0;i<999999999;i++){}
resolve('foo')
});
p.then(function (value) { console.log(value);});
console.log('bar');
I am expecting to see :
bar // printed immediately
foo // printed after the loop finishes
Instead, they are both printed after the loop completion.
How to make the loop block run asynchronously?
Ps. Apologies for the indentation/formatting, I had to write this from a phone.
Thanks
You seem to assume that "asynchronous code" involves concurrency, in the sense that code will run at the same time in another thread. That is not the case. Unless you start another thread by purpose, JS itself will run in a single thread. Therefore no matter what you do with promises: Either the loop runs first and then the logs run or the logs run first and then the loop runs.
You could also achieve concurrent execution through multitasking: If you stop the loop inbetween, other code can run in the meantime:
(async function() {
while(true) {
console.log("loop");
await Promise.resolve();
}
})();
console.log("in the meantime");
But there's nothing asynchronous about your promise. Creating a promise starts the execution of the function, and JS always runs to completion.
Typically, a promise is used to initiate something asynchronous, like an API call, or even a plain setTimeout, that runs outside JS's thread. Your code, however, will iterate through the empty loop bajillion times, and only after that any following lines will be run.
Replace the empty line with a timeout, and it will become async:
var p = new Promise(resolve => {
setTimeout(() => resolve("foo"), 2000);
});
p.then(function(value) {
console.log(value);
});
console.log('bar');

Why does 2nd JS async function call wait for 1st to finish?

I was under the impression that a call to an async function would not be blocking unless the await keyword is used. However for the following code:
EDIT: I am editing the example to better illustrate my question.
function sum1Through(n) {
console.log('Starting computation for ' + n);
let result = 0;
for (let i = 1; i <= n; i++) {
result += i;
}
console.log('Finished computation for ' + n);
return result;
}
function asyncSum1Through(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(sum1Through(n));
}, 0);
});
}
asyncSum1Through(1000000000);
asyncSum1Through(2);
sum1Through(3);
The order of output is:
Starting computation for 3
Finished computation for 3
Starting computation for 1000000000
Finished computation for 1000000000
Starting computation for 2
Finished computation for 2
Why is the 2nd call blocked until the 1st call completes but the 3rd call is not?
If your endpoint is console.log() then obviously "all of your functions" are asynchronous. Not only for one reason but two.
In the asyncSum1Through() function the console.log() instructions are invoked within setTimeout's callback which makes them asynchronously invoked.
Even in sum1Through(3) function console.log() is by default invoked asynchronously but this is not our concern here.
So the output is very "as expected". Whereas the last instruction; namely... sum1Through(3); which happens to be synchronous up until console.log(), comes out first (since console.log() registers into the event queue first) and then the others follow as in the order they have entered into the event queue.
In fact it could have been more convoluted if you hadn't mixed in setTimeout() into your promises but that's totally another topic called microtasks.
Note : Oh..! If your question is; amongst the two asnc functions why the second waits for the first one to finish although the second one would take much less time to run? Then you should understand that asynchronous tasks does not have any privilage on the CPU work currently being consumed by the CPU thread. JS is a single threaded language and any task gets the right to render first has to finish first before the next. Asynchronicity in JS is meant tasks grant priority when other are waiting idle for an IO action which do not own the CPU thread JS running on.
Using an async function doesn't mean that it will be executed "asynchronously". What it offers is that using the await it can be paused and wait for something.
Async Function
An async function can contain an await expression, that pauses the
execution of the async function and waits for the passed Promise's
resolution, and then resumes the async function's execution and
returns the resolved value.
All the code in your function is synchronous and runs immediately, before the call returns the promise. You would need to actually await something to have the code after the await run later.
Async functions are not starting a thread or running anything in parallel, and they cannot block their caller either. They just provide a simple syntax to write sequential code with promises.

Categories

Resources