I'm trying to figure out how promises are handled in the runtime environment. Are they moved into the web API container until they resolve and then pushed into the callstack when .then is called? Here is some example code. Console.log runs before the promises which leads me to believe somewhere along the way they end up in the queue. I also noticed I can put a function in a .then and the returned promise will fill that functions parameters.
// asynchronous test
let promiseWhatever = new Promise( function(resolve, reject){
// variable to be chained later and passed in function argument
let chainedVariable = 'I am chained';
resolve(chainedVariable);
reject('rejected promise');
});
let promiseMe = function(promiseResult) {
let message = `${promiseResult} to my computer`;
return Promise.resolve(message);
// resolves here to be passed onto the second chained then
};
function hello() {
promiseWhatever
.then(promiseMe)
// how does promiseMe take in the result for its argument?
// then returns another promise and you can chain them
.then( function(fulfilled){
console.log(fulfilled);
}) // is fullfilling the code to display the string to the console.
.catch( function(err) {
console.log(err);
});
console.log('hello'); // logs first to the console
};
hello();
First off a promise is just a notification scheme. The underlying asynchronous operation (whatever code resolves or rejects the promise) that would typically be outside of Javascript (using native code) such as an incoming webSocket message or an ajax response or something like that.
All promise engines use the event queue. When a promise is resolved, they post an event to the event queue in order to trigger the appropriate .then() or .catch() handler to be called. It is not required by the language or promise specification, but a number of implementations use a special event queue for promise callbacks that is checked along with other types of event queues.
It is required by the promise specification that a .then() or .catch() handler is always called asynchronously AFTER the current event loop code has finished even if the promise is resolved immediately. That's why your console.log('hello') shows before the console.log() inside the .then() handler. This is by design and is done in order to create consistency on when a promise calls it's handlers (always after the current event loop code completes).
Are they moved into the web API container until they resolve and then pushed into the callstack when .then is called?
When a promise is resolved an event is inserted into the event queue which will cause the appropriate .then() callbacks to get called after the current event loop code has completed (on a future event loop cycle).
It's not clear what you mean by "web API container" so I can't comment on that.
I also noticed I can put a function in a .then and the returned promise will fill that functions parameters
Yes, this is how promises work. A .then() handler is passed a single argument that represents the resolved value of the promise. A .catch() handler is passed a single argument that represents the reject reason.
Related
I already know how Promise works but I'm trying to dive deeper more to strengthen my fundamental!
So after reading so many stackoverflow posts, I found out, there's two major array properties in every promise object called onFulfillment and onRejection which are empty array and we use .then to fill the onFulfillment array and .catch or .then's second argument to fill onRejection empty array!
And once our promise is settled, functions from those arrays are put into the microtask queue for later execution.
If our promise was resolved, functions from hidden onFulfillment array will be put onto the task queue but if our promise was rejected, functions from onRejection array will be put onto the task queue for later execution, however, when I tested this theory, that doesn't seem to be the case!
I'm sure my English is not easy to understand so here's some code that will hopefully give you all some sense of what I'm talking about.
let p = new Promise(function (resolve, reject){
setTimeout(reject, 1000)
})
p.then(x => console.log('done'))
.then(null, x => console.log(true))
p.catch(x => console.log('done'))
We have one .then and one .catch which we put into the onFulfillment and onRejection array respectively and after 1000 ms, what function is put onto the microtask queue depends on if our promise was resolved or rejected. In our case, its being rejected so it only makes sense to put the .catch's function onto the microtask queue however, it seems like even .then's function is being put onto the task queue!
It doesn't literally run but it's evaluated to a rejected promise, but if thats the case, .then's function was put onto the microtask queue and run/evaluted to which means its incorrect that what function is run depends on if our promise was resolved or rejected, it seems like both .then and .catch will run/evaluated.
We use .then to fill the onFulfillment array and .catch or .then's second argument to fill onRejection empty array!
Not exactly. then always puts handlers in both arrays, to be notified when the promise settles. These handlers (which are not the passed arguments!) then
either call the respective callback with the result/error value, and resolve the promise which .then() had returned with the call result,
or, if no callback for the respective state was passed, directly propagate the value to the promise which .then() had returned
You can do .then(onFulfilled, onRejected), .then(onFulfilled, null), .then(null, onRejected) or .then(null, null) - they all install two handlers.
I'm pretty new to JavaScript (using Node.js) and still learning. I try to wrap around my head with promises and I got into this situation where I don't understand if there is a difference between this code:
promiseFunc().then(() => {
anotherPromiseFunc() // I dont need .then() here, just want to save some data to DB
});
doSmthElse()
and this code:
promiseFunc().then(async () => {
await anotherPromiseFunc() // I dont need .then() here, just want to save some data to DB
});
doSmthElse()
If I don't use .then() in the first case, does it mean there is a possibility that doSmthElse() will be executed before anotherPromiseFunc() is executed? So in order to prevent that, I have to add async/await? Or all code in .then() block is being waited to execute anyway before doing something else?
Note 1: I don't want to chain those promises, because there is more code in my case, but I just simplified it here.
Note 2: I don't use catch because if error will rip through I will catch it later.
If I don't use .then() in the first case, does it mean there is a possibility that doSmthElse() will be executed before AnotherPromise() is executed?
doSmthElse() is guaranteed to be executed before anything in the fulfillment handler¹ is executed. Promise fulfillment and rejection handlers are always invoked asynchronously. That's true whether you declare the handler function using async or not.
For example:
console.log("before");
Promise.resolve(42)
.then(result => {
console.log("within", result);
});
console.log("after");
The output of that is:
before
after
within 42
So in order to prevent that, I have to add async/await?
Where you've added async/await in your example doesn't change when doSmthElse() is executed.
If you want doSmthElse() to wait until the promise has been fulfilled, move it into the fulfillment handler.¹
If your code were inside an async function, you could use await instead, like this:
// Inside an `async` function
await promiseFunc().then(() => {
anotherPromiseFunc();
});
doSmthElse()
That would do this:
Call promiseFunc() and get the promise it returns
Hook up a fulfillment handler to that promise via then, returning a new promise; that new promise is the operand to await
Wait for the promise from #1 to settle
When it does, your fulfillment handler is executed and runs anothterPromiseFunc() but doesn't wait for the promise it returns to settle (because, as you said, you're not returning that promise from the fulfillment handler).
At this point, the promise from #2 is fulfilled because your fulfillment handler has (effectively) returned undefined, which isn't a thenable (loosely, a promise), so that value (undefined) is used to fulfill the promise from #2.
Since the promise from #2 has been fulfilled, await is satisfied and doSmthElse() is executed.
¹ the function you pass then as its first argument
I assume that Promise() just stands for some function call returning a Promise:
You could say that .then registers an event listener that runs as soon as the promise settles => the task is finished. It still runs asynchronously So in your example doSmthElse will still run even if the promise hasn't been settled (so if the promise doesn't settle immediately doSmthElse will be called before the function inside .then)
To let your code run "in order". You would have to use await to ensure that doSmthElse is called after the promise settled or you could put doSmthElse into the .then block.
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!!!
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.
I have read on multiple websites, that the .then() method from the promise.prototype returns a promise. Unfortunately, no source describes the reason behind this.
The then() method returns a Promise. It takes up to two arguments: callback functions for the success and failure cases of the Promise. - developer.mozilla.com
Why/When would someone need this returned promise object, how is this promise object related to the original object.
Thanks a lot for helping.
A promise is executed asynchronously, you never know when the then() will be executed.
And a promise can return a promise, this allows you to chain asynchronous events handling in singles lines of code.
Example code given by Mozilla:
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
It avoids the "pyramid of doom" :
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
There are three main aspects to the fact that .then() returns a promise.
The first is that you can chain operations like this:
a().then(b).then(c).then(d)
Because .then() returns a new promise, the following .then() handlers will not be executed until that new promise resolves. If b and c are synchronous, then that new promise will resolve when they return and the chain will continue when first b is done and then when c is done.
The second is that the new promise can be influenced by what the .then() handler returns. This allows b, c and d to be asynchronous operations that, themselves returns promises and the chain will be sequenced appropriately. So, imagine that b and c both return promises themselves.
First you get a() returning a promise. When that resolves resolves, its .then() handler gets called. That will then run b. If b() is also an async operation and it returns a new promise, then the promise that a.then(b) returns that all the other .then() handlers are linked to will NOT be resolved until that new promise that b returned is resolved. This allows a .then() handler to insert a new asynchronous item into the chain. This is a very important aspect of chaining promises. .then() handlers can insert them own asynchronous operations into the chain and they can even do it conditionally based on prior results or current state.
If a().then(b) just returned the same promise that a() returns, then all the subsequent .then() handlers would not be able to "wait" for the promise that b() returns because they would have been linked to the a() promise and it has already resolved. It is the returning of this new promise that allows the function inside the .then() handler to influence the subsequent chain because that new promise is influenced by what the .then() handler returns.
The third aspect is that the return value of the .then() handler can influence the resolved value of the new promise and that is what is passed to the next .then() handler in the chain. If a().then(b) just returned the same promise that a() returns, then all the subsequent .then() handlers would just see the same resolved value from a() because that resolved value was already set when a() resolved which is before a().then() has called its .then() handler. These subsequent .then() handlers wouldn't be able to inherit a new resolved value from then code inside the .then() handler.
Let's look at a specific scenario. I'll use a delay method as a simple example of a function that returns a promise that resolves in the future.
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => resolve(val), t);
});
}
Then, define several different async functions:
function a(val) {
return delay(100, val + 1);
}
function b(val) {
return delay(50, val + 10);
}
function c(val) {
return val * 100;
}
Now, put them all in a chain:
a(100).then(b).then(c).then(val => {
console.log("all done: ", val);
});
Here's what happens step by step:
a(100) is called. This calls delay (which sets a timer) and returns a promise which I will call a1_promise just for purposes of describing things here.
Then, because we're doing a(100).then(b), we take the return value from a(100) which is the a1_promise and call a1_promise.then(b). That stores away the b function as a .then() handler function to be called sometime in the future when a1_promise is resolved (not right now). That then returns a new promise which I will call a2_promise.
Then, because we're doing a(100).then(b).then(c), we take the return value from a(100).then(b) which is the a2_promise and call a2_promise.then(c). That stores away the c function as a .then() handler function to be called sometime in the future when a2_promise is resolved (not right now). That then returns a new promise which I will call a3_promise.
Then, because we're doing a(100).then(b).then(c).then(...), we take the return value from a(100).then(b),then(c) which is the a3_promise and call a3_promise.then(c). That stores away our last anonymous function as a .then() handler function to be called sometime in the future when a3_promise is resolved (not right now). That then returns a new promise which I will call a4_promise (which nobody uses).
Now we're done with synchronous execution. Note that a().then(b).then(c).then(...) was all executed synchronously. All three .then() methods have already been called on all the different promises. But, because NONE of the promises created here are yet resolved, none of the .then() handlers have actually been called yet. They've all just been stored away to be called in the future when the promises are resolved.
Now some time passes and the timer created inside of a() fires and resolves a1_promise. That then triggers a1_promise to call any .then() handlers it has and pass it the resolved value of the a1_promise which in this case will be 100 + 1 or 101. Since there is just one .then() handler on the a1_promise and it is the b() function, it will call b(101) now. Executing that will just return a new promise which b() created and returned. We will call that new promise b_promise. Inside the a1_promise() it knows that it created the a2_promise() when a1_promise.then() was previously called so it knows that when it executes that stored .then() handler and that .then() handler executes and returns a new promise, then it holds off on resolving the a2_promise that it created until thatb_promiseis resolved. In this way, you can see that further execution of the chain is now controlled by theb_promise, thus the code executing inb()and the promise is returned are inserted into thea().then().then().then()chain holding off future.then()handlers until theb_promise` is resolved.
Now some more time passes and the timer created inside of b() fires and resolves the b1_promise with a newly modified value of 101 + 10 which is 111. This tells the a2_promise that it can now resolve with that value.
The a2_promise can then call it's .then() handler and can execute c(111) which again just like in step 6 returns c_promise which is not yet resolved.
Some time passes and c_promise resolves with a value of 111 * 100 which is11,100. That tells thea3_promise` that it can now resolve with that value.
The a3_promise can then call it's .then() handler which is our arrow function at the end of the chain and we get a console.log() showing 11000 as the final value.
This is the good part of a Promisse.
You can chain a lot of methods where which one depends from a method result (in this case Promisse.resolve) above, for example. Like this