Is Promise.resolve a asynchronous function? - javascript

When I have the following code:
var promise1 = Promise.resolve([1, 2, 3]);
promise1.then((value) => {
console.log(value);
// expected output: Array [1, 2, 3]
});
console.log('end of script');
I know that end of script is returned earlier because the promise is asynchronous. But at what point of execution does it become asynchronous?
Is Promise.resolve() asynchronous?
Or is .then asynchronous or even both functions?
Is there some other mechanism playing under the hood?
(was a hell to google because I get only results of the new async await features)

Promise.resolve([1, 2, 3]);
Is Promise.resolve() asynchronous?
No that's just a regular function call. It will return a result immediately.
Or is .then asynchronous or even both functions
No. Both aren't asynchronous in the sense that
promise1.then((value) => console.log(value));
will immediately return a new Promise for chaining.
However a Promise definitely resolves asynchronously, which means that the inner function (value => console.log(value)) is called definitely after your whole synchronous code executed.
Is there some other mechanism playing under the hood?
Yes there is a "magic" event loop in the background which manages all the async events.

All answers are nice but i would like to mention a little subtle point here. In JS not all asynchronous animals are equal. Promises use microtask queue while the oldschool async callbacks use the event queue.
So as for below code please try to guess the order of logs before you run it..
console.log("Code starts here");
setTimeout(console.log,0,"setTimeout resolved");
Promise.resolve("promise resolved")
.then(s => (console.log(s), "yet another promise resolved"))
.then(s => console.log(s));
console.log("Code ends here")
So as you see microtask queue which is used by Promises are privileged to the event queue and when it's time comes the instruction at the head of the microtask queue takes precedence compared to the poor one at the head of the event queue even though they both resolve at the same time just like above.

Here is the exact order of what goes on. Before we begin, you should note that Promise objects are always in one of three states:
Waiting for evaluation to complete.
Resolved with a final value.
Rejected with a "reason" value.
First, promise1 is assigned a promise that is in the "Resolved" state with a final value of [1,2,3]:
var promise1 = Promise.resolve([1, 2, 3]);
Next, we ask that, once promise1 enters its resolved state, we log its final value. However, .then(), .catch(), etc. in promises are never evaluated until the whole program is passed through and execution enters the Javascript event loop. Thus, this chunk of code registers the future action that is to be completed but does not actually complete it; this chunk of code returns right away without completion occurring.
promise1.then((value) => {
console.log(value);
// expected output: Array [1, 2, 3]
});
After that, we print some text:
console.log('end of script');
At this point, Javascript's execution returns to its event loop, it finds the .then() that we registered earlier, and it carries out the relevant function ((value) => console.log(value)).
There is a helpful article describing how the event loop works with promises here: https://blog.sessionstack.com/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with-2f077c4438b5

But at what point of execution does it become asynchronous?
When something happens "out of order".
Is Promise.resolve() asynchronous?
Not usually. But yes, depending on what argument you call it with it sometimes does schedule the assimilation of a thenable for later. In your case, passing an array, no there's nothing asynchronous going on.
In any case, it always immediately returns a promise.
Or is .then asynchronous or even both functions?
Yes. then does always schedule the callback function that you pass in for later.
Of course, it does always immediately return a promise as well.
In general, we can say that observing a promise result is always asynchronous.
When asking whether a function is asynchronous, it's unfortunately ambiguous whether we mean that the function is called asynchronously (later), or causes another function to be called asynchronously (by scheduling an asynchronous event).

Related

How does the JS event loop behave when a Promise's resolution depends on setTimeout?

console.log('1')
setTimeout(() => {
console.log('2')
}, 0)
function three() {
return new Promise(resolve => {
setTimeout(() => {
return new Promise(resolve => resolve('3'))
},0)
})
}
three().then(result => console.log(result))
console.log('4')
This code snippet outputs 1 4 2
This is the behavior I would expect based on my understanding of javascript's event loop and concurrency model. But it leaves me with some lingering questions.
Before getting to those questions, I'll first break down my understanding of this code snippet.
Why code outputs 1
no explanation needed
Why code outputs 4
the callback that outputs 2 gets loaded into the event queue (aka macro task queue) after 0ms, but doesn't get executed until the main call stack is emptied.
even if three was a promise that was immediately resolved, its code is loaded into the job queue (aka microtask queue) and wouldn't be executed until the main call stack is emptied (regardless of the contents of the event queue)
Why code outputs 2
after console.log(4) the main call stack is empty and javascript looks for the next callback to load on the main stack. It's pretty safe to assume that at this point, some "worker thread" had already put the callback function that outputs 2 onto the macro task queue. This gets loaded onto the stack and 2 is output.
Why code does NOT output 3
This is where its a little blurry for me. The function three returns a promise that is then-ed in the main thread. Callback functions passed through then are loaded onto microtask queue and executed before the next task in the macrotask queue. So while you might think it'll run before the callback that logs 2, its actually theoretically impossible for it to run at all. That's because the Promise is only resolved via the callback function of its setTimeout, and that callback function (because of setTimeout) would only run if the main execution thread (the same thread that's waiting for the promise to resolve) is empty.
Why does this bother me
I'm trying to build a complete theoretical mental model of how javascript handles concurrency. One of the missing pieces in that model is the relationship between network requests, promises, and the event loop. Take the above code snippet, and suppose I replace three's setTimeout with some sort of network request (a very common thing in async web development). Assuming that the network request behaves similarly to setTimeout, in that when the "worker thread" is done, a callback is pushed to the macro task queue, it's hard for me to understand how that callback even gets executed. But this is something that happens literally all the time.
Can someone help me understand? Do I have any missing gaps in my current understanding of js concurrency? Have I made an incorrect assumption? Does any of this actually make any sense? lol
Why code does NOT output 3
In this code:
function three() {
return new Promise(resolve => {
setTimeout(() => {
return new Promise(resolve => resolve('3'))
},0)
})
}
three().then(result => console.log(result))
You never resolve the first Promise that three() creates. Since that's the one that is returned form three(), then the .then() handler in three().then(...) is never called.
You do resolve the promise created inside the timer, but you're returning that promise only to the timer callback which does nothing.
If you change your code to this:
function three() {
return new Promise(resolve => {
setTimeout(() => {
resolve('3');
},0)
})
}
three().then(result => console.log(result))
Then, you would see the 3get output.
So, this doesn't have anything to do with the event loop or how it works. It has to do with not resolving the promise that three() returns so the .then() handler on that promise never gets called.
I'm trying to build a complete theoretical mental model of how javascript handles concurrency. One of the missing pieces in that model is the relationship between network requests, promises, and the event loop. Take the above code snippet, and suppose I replace three's setTimeout with some sort of network request (a very common thing in async web development). Assuming that the network request behaves similarly to setTimeout, in that when the "worker thread" is done, a callback is pushed to the macro task queue, it's hard for me to understand how that callback even gets executed. But this is something that happens literally all the time.
Network requests and promises and timers all go through the event loop. There are very complicated rules about how multiple events in queue at the same time are prioritized relative to one another. .then() handlers are generally prioritized first.
Think of the Javascript interpreter as this simplistic sequence.
Get event from event queue
If nothing in the event queue, sleep until something is in the event queue
Run callback function associated with the event you pull from the event queue
Run that callback function until it returns
Note, it may not be completely done with its work because it may
have started other asynchronous operations and set up its own
callbacks or promises for those. But, it has returned from the
original callback that started it
When that callback returns, go back to the first step above and get the next event
Remember that network requests, promises, timers and literally ALL asynchronous operations in node.js go through the event queue in this manner.
Why you assume that network request would behave as setTimeout?
It is a Promise which resolved() would go in microtasks

Difference in timing when returning a resolved Promise

I have a function that does a bunch of work then returns a resolved Promise. Is there a difference in the timing when each will be resolved?
Option 1
function returnPromise() {
// do a bunch of stuff
return Promise.resolve();
}
and this way:
Option 2
function returnPromise() {
return new Promise((resolve, reject) => {
//do a bunch of stuff
resolve();
});
}
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called? I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
Is there a difference in the timing when each will be resolved?
No difference. The Promise executor (the callback you pass to new Promise()) is called immediately and synchronously. So, in BOTH cases, you are immediately and synchronously returning an already resolved promise and all the code in your function has already executed.
There should be no meaningful difference in execution timing. Of course, one might take slightly different number of CPU cycles to execute, but both have the exact same outcome and both immediately return a promise that is already resolved so there should be no difference to the calling code at all.
Promise.resolve() is just meant as a more compact (and probably more efficient) means of creating an already resolved promise.
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called?
They both return when all your work is done and they return an already resolved promise. This is because the executor callback to new Promise() is called synchronously (before your function returns).
I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
In this particular circumstance, all your code is run synchronously so there is no particular involvement of the event loop. The returnPromise() function returns (in both cases) when your code in the function is done executing synchronously. There is no async code here.
The event loop gets involved when you do .then() on the returned promise because even though the promise (in both cases) is already resolved, the .then() handler gets queued in the event queue and does not run until the rest of your Javascript after your .then() handler is done executing.
console.log("1");
returnPromise().then(function() {
console.log("2");
});
console.log("3");
This will generate identical output results:
1
3
2
with both versions of your returnPromise() function because .then() handlers are queued until the next tick of the event loop (e.g. after the rest of your current Javascript thread of execution is done).
Is there a difference with doing it this way?
No, both your examples do the exact same thing.
Promise.resolve and Promise.reject are simply static methods on the Promise Class that help you avoid constructing a whole Promise when you don't really need to.

Does the execution finishes after the very first promise is resolved(rejected) in Promise.race?

I can't understand what's Promise.race behavior. Does it stop after the very first promise instance in an array of promises is resolved (rejected), ignoring all the rest?
My goal is to execute all promises in an array. In any sequence but all should be executed.
An example. Lets say that array_of_urls has 10 urls. Will Promise.race execute all 10 promises, in any sequence one by one, or will it stop after the very first?
.then(array_of_urls => {
// array_of_urls == [10 urls]
let array_of_promises = array_of_urls.map((url) => {
return fetch(url).then(res => {
return res;
});
});
return Promise.race(array_of_promises);
})
.then(each_and_every_result => {
// What does happen here? Will this `then` callback be called 10 times or just one?
})
Do Promises have methods to execute all?
PS:
MDN doesn't explain if all will be executed or it will stop:
The race function returns a Promise that is settled the same way as the first passed promise to settle. It resolves or rejects, whichever happens first.
UPD:
Sorry, didn't explained it correct. I do need to execute all promises in an array but not the way Promise.all does it. Yes, Promise.all executes all, but it waits until all of them executed, collecting their results and then returns one array with all their results in it. And I need to call a cirtain callback every time one of those 10 is fullfilled. That is without waithig all of them to be collescted by Promise.all.
Promises are merely a notification system for asynchronous operations. They don't control the async operations at all. In fact, the opposite is true, the async operations control the promises. So, whether you use Promise.race() or Promise.all() or some other scheme with your promises does not affect the underlying asynchronous operations at all. It only affects which kind of notification you get about the completion of the asynchronous operations.
So, when you use Promise.all() you get a notification when either all the async operations have completed successfully or when one has an error. If one has an error, all the other async operations are still running and will run to their normal completion. Only your Promise.all(...).then() handler will be affected.
When you use Promise.race(), you are just getting a notification when the first async operation finishes. The other async operations will still run to their normal completion.
If you want to be notified when each individual async operation completes, then you just attach a .then() handler to each individual promise and those .then() handlers are not influenced at all by whether you also have a Promise.all() or Promise.race() on the array of promises - that would just be another notification.
I find it works best to think of promises as a notification mechanism for asynchronous operations. They don't control the asynchronous operations at all once they are started. instead, they provide structured notification about what happens with the completion of the asynchronous operations.
// What does happen here? Will this then callback be called 10 times
or just one?
Promises only ever resolve or reject once so your Promise.all(...).then() or Promise.race(...).then() handler will only ever be called once.
Will Promise.race execute all 10 promises, in any sequence one by one,
or will it stop after the very first?
By the time you call Promise.race() your async operations have already been started and they are all already underway. They will all be executed. Promise.race() has no influence on the execution of the async operations themselves - it is just providing a notification about when the first async operation finishes.

Promise.resolve with no argument passed in

In the OpenUI5 code-base I came across this snippet:
// Wait until everything is rendered (parent height!) before reading/updating sizes.
// Use a promise to make sure
// to be executed before timeouts may be executed.
Promise.resolve().then(this._updateTableSizes.bind(this, true));
It looks like the native Promise function is being used, with no argument being passed to it's resolve function which takes an:
Argument to be resolved by this Promise. Can also be a Promise or a
thenable to resolve.
So, since it looks like the promise would simply immediately resolve and invoke then's callback, perhaps the intent is similar to:
var self = this;
setTimeout(function() {
self._updateTableSizes.bind(self, true)
}, 0);
...basically, freeing the JavaScript run-time event-loop to finish other things (like rendering) and then come right back to the callback?
My question is:
Is this a common pattern? Best-practice? Are there any advantages/disadvantages to either approach?
Yes, Promise.resolve() does immediately fulfill with the undefined value that you implicitly passed in. The callback is still executed asynchronously - quite like in the setTimeout snippet you posted.
However, as the comment in the code explains, the intent is not just to execute the callback asynchronously:
Use a promise to make sure to be executed before timeouts may be executed.
Promise callbacks do run before timeouts or other events, and these subtle timing differences are sometimes important. Given that choice of the task loop is usually not important, No this is not a common pattern; but it is a valid pattern that does exactly what you need when you need it.
I noticed the technique in this polyfill: https://github.com/wicg/inert (with comment)
const newButton = document.createElement('button');
const inertContainer = document.querySelector('[inert]');
inertContainer.appendChild(newButton);
// Wait for the next microtask to allow mutation observers to react to the DOM change
Promise.resolve().then(() => {
expect(isUnfocusable(newButton)).to.equal(true);
});

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