Why Javascript waits for promises to fulfil [duplicate] - javascript

This question already has answers here:
Javascript async and await
(3 answers)
Closed 4 months ago.
I'm learning promises and I came across this piece of code
async function main() {
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("hello");
resolve();
}, 1000);
});
console.log("world");
}
main();
The output this produces is "hello world".
What I'm not able to understand is why the inner console log "console.log("world")" is waiting for the promise to resolve.
Am I missing something here, it would be nice if I can get some help understanding this or maybe some link to some documentation for further reading.
Thanks in advance.

Am I missing something here
Bluntly speaking yes, you're missing first word of the second line.
The key to understand what's happen there is await.
You're creating a promise with
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("hello");
resolve();
}, 1000);
});
This promise will start an asynchronous action, that could end somewhere in the future (after 1 sec in this particular case).
You probably supposed that this action should be executed after console.log("world"); and it could happen if there was no await before promise.
But we do have this await so we litteraly said to program "Hey, I want to wait for this action to end, before I'll go farther".
That's why we see printed hello before world.

Await expressions make promise-returning functions behave as though
they're synchronous by suspending execution until the returned promise
is fulfilled or rejected.
Source
Let's break this down step-by-step without overcomplicating things. This is what is happening inside your main() function:
the first line is executed as expected, but the keyword await inside your function stops the progress (the promise must be first fulfilled or rejected)
inside the promise you have setTimout(), another asynchronous function, but this one is not awaited;
setTimeout() is an asynchronous function, meaning that the timer
function will not pause execution of other functions in the functions
stack. In other words, you cannot use setTimeout() to create a "pause"
before the next function in the function stack fires.
source
Yet, the execution seems to be paused, but it is not due to setTimeout() function on its own. It is because the promise waits to be resolved. And when do we resolve it? After 1 second.
The callback inside setTimeout() is executed as expected: console.log('hello') is printed first and the promise is resolved right after with resolve().
With the promise being resolved, the progress finally continues with the console.log('world').
Thus we end up with
// hello
// world
You can try moving the resolve() outside of the setTimeout() and observe how the promise is resolved right away and the printed message is reversed (because, as I said above, setTimout() does not pause the execution of the promise on its own).
async function main() {
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('hello')
}, 1000)
resolve()
})
console.log('world')
}
// world
// hello
To wrap it up:
What I'm not able to understand is why the inner console log >"console.log("world")" is waiting for the promise to resolve.
The console.log("world") is not waiting for the promise, it is waiting for the delay inside setTimeout(). Just as promise is waiting to be resolved: which happens right after the console.log("world").

Because this is how promises work. They are designed to always return a clear result. Read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise for more info.

Related

How are the callbacks of promises put in the micro task queue? [duplicate]

This question already has answers here:
What is the intention behind clause 2.2.4 of Promise/A+ spec?
(1 answer)
Why are javascript promises asynchronous when calling only synchronous functions?
(2 answers)
Why are Q.js promises asynchronous after they have been resolved?
(2 answers)
Closed last year.
As I understand a promise is something that can resolve() or reject(), and this action should be done after some work as completed, so it should be invoked as part of the callback like in this example:
let timeout = new Promise((resolve) => {
console.log('function called');
setTimeout(() => {
console.log("timeout finisced!");
resolve()
}, 1000)
});
timeout.then(() => {
console.log("timeout resolved!")
});
console.log('teminated!');
result
function called
teminated!
timeout finisced!
timeout resolved!
But the thing I can't understand is how they work when there isn't an asynchronous action to do and so, if you think synchronously, the resolve function should be called in the constructor of the promise, even if you don't have a handler for it and then the then() method should be able to handle it after; but from what I can see from this example, the code is executed in the same way.
So can someone explain the thought behind why the following example works in this way?
new Promise(function(resolve) {
console.log('function called')
resolve();
}).then(() => {
console.log('function resolved');
});
console.log('teminated!');
result:
function called
teminated!
function resolved
Edit:
I have mostly understanded what’s happening, the thing that now I am not sure is how this is done.
So correct me if I’m wrong, the .then() method is always put in the micro task queue no matter what, so even if you pass it synchronous code, it is not executed in the stack directly like other synchronous code.
And for that to happen the state of the promise should be fulfilled or rejected, and to do that the function resolve() or reject() should be called.
So now I would like to understand the process that is behind it, like what does the then() method effectively do?
You pass it a callback and that is stored in the promise object or what?
And because the callback is put on the micro task queue after it is fulfilled or rejected, does that mean it is the resolve() function that puts it in the micro task queue?
That should be a reasonable assumption based on this example below; or does the resolve function only change the state and then is the then() method that puts it in the queue?
const p = Promise.resolve();
p.then(() => console.log("callback 1"));
const p2 = Promise.resolve();
p2.then(() => console.log("other micro task"));
p.then(() => console.log("callback 2"));
/*
result:
callback 1
other micro task
callback 2
*/
const p = Promise.resolve();
p.then(() => console.log("callback 1"));
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(), 0)
});
p2.then(() => console.log("other micro task"));
p.then(() => console.log("callback 2"));
/*
result:
callback 1
callback 2
other micro task
*/
The only thing I’m sure of is that there are multiple callbacks for a single promise, they aren’t always executed one by one in order, but there can be another micro task before it like in the first example.
I'm aware that this may be a stupid problem, but for some reason it put's me in confusion, so thank's in advance for the help.
First, promises are async (then part), async/await is built on top of them. And the promise is not a simple async code, but a micro task, its executed after sync code, but before macro tasks (such as timeouts).
So in your case we have sync promise part function called, than sync code teminated, than async part after promise resolved function resolved.
To better undestand how micro/micro tasks and event loop works, I recommend you to check out answers here: Difference between microtask and macrotask within an event loop context

Which part of the Javascript Promise function is asynchronous?

I'm learning Javascript async programming and Promise. I have the following code.
let promiseTest = () => new Promise((resolve, reject) => {
console.log("Inside Promise");
resolve('Promise is resolved');
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");
I have the function "promiseTest". I want to execute that asynchronously. In real world scenario, it could be a function that fetch the web service or query the database. I was expecting to have the following result from the code.
Before Promise
After Promise
Inside Promise
Promise is resolved
I was expecting that "console.log(" Inside Promise") " will be executed asynchronously since it is inside the Promise function. But the actual result is
Before Promise
Inside Promise
After Promise
Promise is resolved
As you see tin the actual result, Inside Promise is executed synchronously and blocking the main thread. Only the code inside "resolve" is asynchronous. Maybe, my current understanding of javascript Promise is incorrect. How do I modify my existing code to make sure the whole function " promiseTest " is executed asynchronously without blocking the main thread.
The executor function is executed synchronously. Promise doesn't make any code asynchronous; its just a mechanism to get notified when something, that is already asynchronous, has completed.
If you want to make a API call, that is already asynchronous and if you use the fetch API, then you don't need the promise constructor because fetch(...) already returns a promise.
Only the code inside "resolve" is asynchronous
In your code, resolve() function is also called synchronously; only the callback function of promiseTest().then(..) is invoked asynchronously.
How do I modify my existing code to make sure the whole function
"promiseTest" is executed asynchronously without blocking the main
thread.
You will have to use another thread. Even if you delay the execution of the promiseTest function using setTimeout, once it is pushed in the call stack, it will execute synchronously. Nothing else will execute when the delayed promiseTest function is being executed.
If delaying the execution is what you want, just wrap the promiseTest function call in setTimeout.
I'd suggest using setTimeout for your promiseTest function, this will give you the expected result.
setTimeout sets a timer which executes a function once the timer expires.
As you can see "After Promise" will be logged before "Promise is resolved", this is entirely expected, since the promise will take some time (in this case 1000 milliseconds) to resolve.
let promiseTest = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Inside Promise");
resolve('Promise is resolved');
}, 1000)
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");

Unexpected order of output UsIng Async-Await in JavaScript, Need Explanations [duplicate]

This question already has an answer here:
Promise starts too early
(1 answer)
Closed 1 year ago.
For the following code:-
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("one");
resolve("data1");
}, 8000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("two");
resolve("data2");
}, 5000)
})
let func1 = async() => {
await p1;
console.log("middle");
await p2;
}
func1();
In my understanding of async-await, the output of the above code should be:
one
middle
two
and the total runtime I expect is 13 seconds
The reason I think this is because with await we can execute the promises in order and the control should move to the next line (i.e console.log("middle")) only after the resolve() of first promise(p1) is invoked. So according to me the code would be run in a way that it encounters the line "await p1;" and then it waits 8 seconds to get resolved and then move to the next line and so on.
But the output I am getting in the console is:
two
one
middle
and the total runtime is around 8 seconds and not the expected 13 seconds.
can someone explain what i am getting wrong here?
The timer callbacks aren't in anyway held up or delayed by the fact you're awaiting a completely separate promise.
Your confusion might be the common one of thinking promises do something. :-) They don't. The function you pass to new Promise (the promise executor function) synchronously and immediately when you call new Promise, not later when you use the promise. Its purpose is to start the asynchronous process that the promise will observe/report the completion of. So your setTimeout calls are executed right away, one right after the other. Since you're doing the "one" and "two" console.logs in the setTimeout callback, you see "two" after five seconds and "one" three seconds later (after eight seconds).
You don't see "middle" until the second promise is fulfilled because (as I think you understand), your await makes the code in that async function wait for the first promise to be settled before continuing. But that await doesn't have any effect on when the timer callback runs.
Promises are run as soon as they are instantiated. So in your example both p1 and p2 execute as soon as you create the promise. They both set a specific timeout that resolves the promise by writing to the console and calling resolve.
Then, you wait for p1 to resolve. It takes 8 seconds, as expected from the timeout. But before that happens, the timeout for p2 ends, so the "inner" part of the promise is called, writing two to the console and resolving p2.
Once the 8 seconds elapse, p1 writes one to the log and resolves. Then your code continues executing, writing middle. The final await does nothing, as p2 has already resolved when it is invoked.
For the code to work as you want, you should create p2 after the await p1 line, or, even better, chain p1 and p2 using .then(), so that p2 starts running once p1 has resolved.

Promises: why is the resolve executed after sync code and before async one

I have the following code:
const doWorkPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('#2 (async call)');
}, 0);
resolve('#3 (async call?)');
console.log('#1 (sync call)');
});
doWorkPromise.then((result) => {
console.log('Success!', result);
}).catch((error) => {
console.log('Error!', error);
});
The output is:
#1 (sync call)
Success! #3 (async call?)
#2 (async call)
I know that sync code lands on the call stack and the async code registers event-callback pair at the Node APIs, where the callback is moved to the callback queue after the event. The event loop is then going to take elements out of the callback queue only when the call stack is empty. Therefore, I expected to have the sync code executed first and then the async one in order, because the timeouts are 0s, like:
#1 (sync call)
#2 (async call)
Success! #3 (async call?)
Can someone please explain why resolve is executed before '#2 (async call)'?
reject is never executed.
resolved is executed before #2 because:
setTimeout puts a function on the time out queue
resolve resolves the promise
console.log logs #1
The function finished
doWorkPromise.then assigns a function to run when the promise resolves
The promise is already resolved so that function is executed
After the minimum timeout time passes the function passed to setTimeout is called and logs #2
Your code executes the following synchronously:
resolve('#3 (async call?)');
...so that promise gets immediately in a resolved state. The fact that you have started a timer, as no bearing on the promise... it is unrelated.
So the then callback on that promise will be triggered on the next processing of the job queue, and so you'll see "Success", right after the execution of the main, synchronous code has completed.
Somewhat later (yes, even setTimeout(..., 0) will introduce a small delay), the timer will expire, but that event has nothing to do with any promise.
The common pattern
When you create a promise with new Promise and want it to resolve some time later, then you could indeed use setTimeout, but then the idea is to call resolve only when that timer has expired. Otherwise the timer does not do anything that serves the promise:
setTimeout(() => {
resolve();
}, 0);

Understanding JS Promises

I would like to get a deeper understanding of how Promises work internally.
Therefore I have some sample code:
var p1 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
var p2 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
function chainPromises() {
return p1.then(function(val) {
console.log("p1");
return p2.then(function(val) {
console.log("p2");
return val;
});
});
}
chainPromises().then(function(val) {
console.log(val);
});
Here a link to execute this code.
As you would predict, first p1 is resolved, afterwards p2 and in the end the final then prints the resolv value.
But the API ref states the following:
"then" returns a new promise equivalent to the value you return from
onFulfilled/onRejected after being passed through Promise.resolve
So it would be interesting to know WHEN exactly the "then" function is executed?
Because the final "then" in the code is chained to the chainPromises(), I first thought that
it would execute after the function chainPromises() returns something (in this case another promise).
If this would have been the case the "val" of the final "then" function would be the returned promise.
But instead, the final "then" waits until all promises inside the first "then" which are returned have been resolved.
This absolutely makes sense because in this way, the "then" functions can be stacked, but
I do not really get how this is done, since the API spec. does not really cover what "then" returns and when the "then" functions is executed.
Or in other words, why does the final "then" function wait until all the Promises are resolved inside the chainPromises() function instead of just waiting for the first returned object as the API doc says.
I hope I could make clear what I mean.. :)
About Promise resolution
The thing you're witnessing here is called recursive thenable resolution. The promise resolution process in the Promises/A+ specification contains the following clause:
onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)
The ES6 promise specification (promises unwrapping) contains a similar clause.
This mandates that when a resolve operation occurs: either in the promise constructor, by calling Promise.resolve or in your case in a then chain a promise implementation must recursively unwrap the returned value if it is a promise.
In practice
This means that if onFulfilled (the then) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.
This means the following:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
So for example:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
And that:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
Is it a good idea?
It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.
In other languages
It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to call Task.Unwrap on a task in order to wait for its chain to resolve.
Let's start with an easy perspective: "chainPromises" returns a promise, so you could look at it this way:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
Generally speaking, when returning a promise from within a "then" clause, the "then" function of the encapsulating promise will be marked as finished only after the internal "then" has finished.
So, if "a" is a promise, and "b" is a promise:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
So the output will be:
B!
Done!
Notice btw, that if you don't "return" the internal promise, this will not be the case:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
Here we can't know what would be outputted first. It could be either "B!" or "Done!".
Please check the below example regarding how promises works:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1: shoe ticket');
console.log('person2: shoe ticket');
const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ticket');
}, 3000);
});
promiseGirlFriendBringingTickets.then((t) => {
console.log(`person3: show ${t}`);
})
console.log('person4: shoe ticket');
console.log('person5: shoe ticket');
Promise then return promise object, not promise's resolved value. I forked your JsFiddle, and added some of mine try this.
promise.then is executed right after that promise object is resolved.
I do not know how this is done in actual promises libraries, but I was able to re-create this functionality in the following way:
1) each promise has a waitingPromises property;
2) then method returns a new promise, and the original promise's waitingPromises property points to the new promise.
In this way, the chain of .then()s creates a structure that is similar to a linked list or rather a tree (each promise can have several waiting promises). A promise can be resolved only after its 'parent' promise has been resolved. The .then method itself is executed immediately, but the corresponding promise that it creates is resolved only later.
I am not sure this is a good explanation and would love to learn about other possible approaches.
Normally code is synchronous - one statement executes like (fileopen) and there is a guarantee that the next statement will execute immediately afterwards like filewrite()
but in asynchronous operations like nodejs, you should assume that
you have no idea when the operation will complete.
You can't even assume that just because you send out one request first, and another request second, that they will return in that order
Callbacks are the standard way of handling asynchrnous code in JavaScript
but promises are the best way to handle asynchronous code.
This is because callbacks make error handling difficult, and lead to ugly nested code.
which user and programmer not readble easily so promises is the way
You can think of Promise as a wrapper on some background task. It takes in a function which needs to be executed in the background.
The most appropriate place to use a promise is where some code is dependent on some background processing and it needs to know the status of the background task which was executed. For that, the background task itself accepts two callback resolve and reject in order to convey its status to the code which is dependent on it. In layman terms, this code is the one behind it in the promise chain.
When a background task invokes resolve callback with some parameter. it's marking the background operation successful and passing the result of the background operation to the next then block which will be executed next. and if it calls reject, marking it as unsuccessful then the first catch block will be executed.
In your custom promise, you can pass an error obj to the reject callback so that next catch block is aware of the error happened in the background task.

Categories