Let's say I have a Promise like this:
var promise = new Promise(function(resolve, reject) {
// Do some async thing
});
promise.then(function(response) {
// Then do some other stuff
});
What happens if the async Promise completes before I call .then()? Normally, I'd only have long running tasks in the Promise function, but what if it completes really quickly one time?
As expected: then callback will get called immediately in this case if then was called after promise has already resolved.
It's easy to test:
var promise = new Promise(function(resolve, reject) {
resolve(123);
});
setTimeout(function() {
promise.then(function(response) {
alert(response);
});
}, 1000)
As others have already pointed out, you can add callbacks with .then before or after the promise has been resolved, and you can even add more than one callback.
These callbacks will be called in the order they were added, but always asynchronously, after the current turn of the event loop. So if the promise has already been resolved when you add a .then, your handler will be called immediately, but in the "ascynchronous sense".
The Promises/A+ spec says:
[...] onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack.
A promise has state, which means that even after the promise gets fulfilled, you can attach callbacks using .then to it, and they will be called, with the same result as if the promise was fulfilled after they were attached.
Fulfilled is the final state of a successful promise. This means that you can attach more handlers to the fulfilled promise in the future, using the promise as a cache for the original response.
.then() on MDN
then()
Calls one of the provided functions as soon as this promise is either
fulfilled or rejected. A new promise is returned, whose state evolves
depending on this promise and the provided callback functions.
The appropriate callback is always invoked after this method returns,
even if this promise is already fulfilled or rejected. You can also
call the then method multiple times on the same promise, and the
callbacks will be invoked in the same order as they were registered.
The then callback will never get called before the promise is resolved, which is what I think you mean by complete. However, if a promise is resolved before it is returned from a function, any additional success callbacks chained after that moment will still be executed. For example,
function getMeAResolvedPromise() {
var prom = new Promise();
prom.resolve('some val');
return prom;
}
...
getMeAResolvedPromise.then(function(result) {
// this will still be executed
});
Related
What does resolve actually do?
Consider the code below.
It prints : 1 3 4 5 6 9 7 10 11 2.
Irrespective of where resolve is written, it prints the same!
Can someone explain why this happens?
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
.then(() => {
console.log(9);
})
.then(() => {
console.log(10);
})
.then(() => {
console.log(11);
})
;
// resolve()
}).then(() => {
console.log(5);
new Promise((resolve, reject) => {
console.log(6);
resolve();
}).then(() => {
console.log(7);
});
})
What does 'resolve' actually do?
Calling resolve(x) does three things.
It changes the internal state of the promise to fulfilled. Once the state is changed to fulfilled, the promise state cannot be changed again. This is a one-way, permanent change.
It sets the value x (whatever single argument you pass to resolve) as the resolved value of the promise (this is stored internal to the promise). If nothing is passed to resolve(), then the resolved value is undefined.
It inserts an event into the event queue to trigger the .then() handlers of this current promise to get called upon an upcoming cycle through the event loop. This schedules the .then() handlers to run after the current thread of Javascript execution finishes.
I'll explain the sequence you see in the console, but first here are a few points that will help to understand this:
The promise executor function (the callback passed to new Promise(fn)) is called synchronously (in the midst of the current thread of execution).
When a setTimeout() timers fires (internal to the JS engine), the timer callback is inserted in the event queue and will be picked up on a future cycle of the event loop.
When a promise resolves, an event is inserted into the event queue and will be picked up on a future cycle of the event loop.
There are multiple types of event queues in the event loop and not all have the same priority. In general promise events will be picked up before most other types of events though it's possible this can vary a bit according to the implementation. So, when multiple types of events are both put in the event queue so they are in there at the same time, this can affect which one gets called first.
Multiple .then() or .catch() handlers that are added to the event queue are handled in the order (relative to each other) that they were originally triggered in a FIFO basis (first-in-first-out).
When promise chaining with something like fn().then(f1).then(f2).then(f3) keep in mind that each .then() returns a new promise that will have its own time that it gets resolved or rejected, after the one before it and depending upon what happens in its handler function.
So, here's the sequence of events in your code:
The first promise executor function is called, thus you get the output 1
A timer is created with a timeout of 0. At some point very soon, a timer callback event will be added to the event queue.
You call resolve() on that first promise. This inserts an event/task into the promise queue to call its .then() handlers on a future cycle of the event loop. The rest of this sequence of Javascript code continues to execute. But, notice that there are not yet any .then() handlers on that first promise as its chained .then() methods haven't yet been executed.
You create a second promise and its executor function is called immediately which outputs 3.
You call resolve() on that second promise. This inserts an event/task into the promise queue to call its .then() handlers on a future cycle of the event loop. The rest of this sequence of Javascript code continues to execute.
.then() is called on that second promise. This registers a .then() handler callback function in that second promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (third promise). This registers a .then() handler callback function in that third promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (fourth promise). This registers a .then() handler callback function in that fourth promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (fifth promise). This registers a .then() handler callback function in that fifth promise (adds it to an internal list) and returns a new promise.
The executor function from the very first promise finally returns.
.then() is called on the very first promise. This registers a .then() handler callback function in that first promise (adds it to an internal list) and returns a new promise.
Because the .then() handler from the second promise ran before the .then() handler from the first promise, it gets put into the tasks queue first and thus you get the output 4 next.
When this .then() handler runs, it resolves the promise that it created earlier, the third promise and it adds a task to the promise queue to run its .then() handlers.
Now, the next item in the task queue is the .then() handler from the first promise so it gets a chance to run and you see the output 5.
This then creates another new promise with new Promise(...) and runs its executor function. This causes the output 6 to show.
This new promise is resolved with resolve().
Its .then() is called which registers a .then() callback and returns a new promise.
The current sequence of Javascript is done so it goes back to the event loop for the next event. The next thing that was scheduled was the .then() handler for the fourth promise so it gets pulled from the event queue and you see the output 9.
Running this .then() handler resolved the fifth promise and inserts its .then() handler into the promise task queue.
Back to the event queue for the next promise event. There we get the .then() handler from the final new Promise().then() in the code and you get the output 7.
The above process repeats and you see the outputs 11, then 12.
Finally, the promise task queue is empty so the event loop looks for other types of events that aren't as high a priority and finds the setTimeout() event and calls its callback and you finally get the output 2.
So, setTimeout() goes last here for a couple of reasons.
Promise events are run before timer events (in ES6), so any queued promise events are served before any queued timer event.
Because all of your promises resolve without actually having to wait for any other asynchronous events to complete (which is kind of not real-world behavior and not typically how or why one uses promises), the timer has to wait until they're all done before it gets its chance to run.
And, a few other comments:
Figuring out the relative firing order of various .then() handlers in different and independent promise chains is sometimes possible (it's only possible here because there are no real asynchronous promise resolves with uncertain resolution times), but if you really need a specific execution order, then it's better to just chain your operations to explicitly specify the order you want things to run in the code. This removes any dependency on minute implementation details of the local Javascript engine and makes the code a ton more self-explanatory. In other words, someone reading your code doesn't have to go through the 22 steps I listed to follow the desired execution order. Instead, the code will just specify the order by direct promise chaining.
In real code, it's unusual to have the orphaned, disconnected promise chains you create inside .then() handlers. Because you are not returning those promise from the .then() handler and thus inserting them in the parent promise chain, there is no way to communicate results or errors back from those disconnected promises chains. While there is very occasionally a reason to code a fire-and-forget operation that doesn't need to communicate at all with the outside world, that is unusual and is usually a sign of problem code that doesn't properly propagate errors and whose results aren't properly synchronized with the rest of what's going on.
when I place 'resolve' behind, it prints the same!
As you've discovered, this doesn't really change anything. The .then() following the new Promise(...) isn't executed until after the executor function finishes running and returns so it doesn't really matter where inside the executor you call resolve(). Said another way, none of the .then() handlers can even be registered until after the promise executor returns so no matter where you call resolve() in the promise executor, the result is the same.
resolve indicate the completion of asynchronous task.
In the below code,
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
You have created new Promise, and immediately resolved it using resolve(), so it does not wait for setTimeout to get executed. The resolve(); is immediately followed by
new Promise, which creates new Promise followed by the execution of immediate then section.
In .then you have not returned any thing, so your then's are not chained properly. Return the value in then to chain it properly.
new Promise((resolve) => {
console.log("1");
setTimeout(() => {
resolve(2);
});
}).then((val) => {
console.log(val);
return "3";
}).then((val) => {
console.log(val);
return "4";
}).then((val) => {
console.log(val);
});
I am new to promises and have studied it. So my code and my understanding:
sql.connect(config).then(function(connection) {
return connection.request().query('select * from Users')
}).then(function(result) {
console.dir(result);
res.send(result);
}).catch((err) => {
console.log(err);
res.send(err)
});
}) // extra?
In the first line, the connect method returns a promise so on that, when I call a function then (if connect had success). The then takes callbacks i.e. "successCB", "failureCB" as arguments which actually represent the result or error returned by the connect promise. Correct?
Also, the "successCB" is returning the promise (from .query).
then is again called on the previous promise returned by then.
In case of then used on connect() why is the then taking a callback and how does it know of connect's success since connect has already returned the result i.e. "successCB"?
I'm not 100% certain if you are correct, but this is how I would explain it. Lets say we have a promise A.
Calling then() always returns a new promise (Lets call it B)
If the callback returns a promise C, then promise B will resolve or fail with the result of promise C.
If any of the callbacks returns a non-promise value X, then promise B will resolve with value X
If an exception was thrown in the callback, then promise B will fail with the exception.
If the main promise A failed, and no failure callback was given, then promise B will also fail with the same error.
Personally I found learning this very confusing, because it requires quite a complex mental model to fully grasp this. The day I fully understood this is the day that I wrote my own Promise class. I would recommend anyone who fully wants to grasp promises in every detail to take the time to do this.
In the first line, the connect method returns a promise so on that, I call a function then (if connect had success).
Almost: the then method is called irrespective of the connect promise's result. Note that the promise is most likely still pending when the then method is called. It is called (obviously) synchronously.
The then takes callbacks i.e. successCB, failureCB as an args which actually represents the result or error returned by the connect promise. Correct?
Those callbacks are registered by the promise object, and one of them will be called later when the promise resolves: it can either fulfil or reject. If the promise never resolves, neither will be called. In your case, you provided just one function, the one that will be called when the promise fulfils.
Also, the successCB is returning the promise (from .query).
True. The promise that was created when the outer then was executed will take over the status/value of the promise that was returned here.
then is again called on the previous promise returned by then.
Yes, but again, it is called immediately. All chained then/catch methods are called synchronously and their job is to register the callbacks and to return a promise.
The asynchronous part is when the respective callbacks are called. This is when the cascading effect takes place. Once the first promise (query()) in the chain resolves, the respective callback is called and that call resolves (fulfils or rejects) the promise that was already returned by then, which triggers a next callback... etc
Order of execution
Part A
sql.connect(config)
calls connect and returns a promise
.then(......)
calls then on the promise of A.1, registers the callback and returns a promise
.catch(.....)
calls catch on the promise of A.2, registers the callback and returns a promise.
This happens to be the last one in the chain, so this promise is the value of the whole expression.
At this point the synchronous part ends. If there is other calling code on the callstack, it gets executed, but eventually the call stack will be empty.
Part B
Then, some time later, there is an event indicating that the promise of A.1 is resolved, let's assume it fulfils (i.e. success). Then the first callback is executed:
connection.request() is executed
it calls request which returns an object with the query method (among others)
.query('select * from Users') is executed
it calls query with the SQL and returns a promise
return is executed
the callback returns the promise of B.2, which becomes linked with the promise that was created in step A.1.
At this point the promise of step A.1, is still pending. Its destiny is tied up now with the promise that was returned by query, B.2. It that one resolves, A.1 will also resolve (with the same state & value/error).
Part C
Then, some time later, there is an event indicating that the promise of step A.1 is resolved, let's assume it fulfils. Then the second callback is executed:
console.dir(result) is executed
res.send(result) is executed
Nothing is returned, so the promise of 1.B fulfils with value undefined
This fulfilment creates a next asynchronous job to execute (part D)
Part D
The promise returned by catch (A.3) resolves with the value with which C.3 resolved, i.e. it fulfils with value undefined. The callback it had registered is not executed, as it is not relevant for this scenario.
Thanks for replies and I have already selected the answer. Based on the input given by you people this is what I have understood further.
sql.connect(config).then(function(connection) {
return connection.request().query('select * from Users')
})
In the code given above, sql.connect part is using an SQL module to call a connect() method which is supposed to return a promise (in case of failure returns an error else a connection object). On connect() we call a then() method which takes a callback function function(connection) to get registered so that can be called later at the point where connect returns a promise (in case of success i.e. connection object) and later
.then(function(result) {
console.dir(result);
res.send(result);
}).
is called on the promise returned by .query('select * from Users') part of the previous .then() method's callback function and so on.
when the call back functions in the myFunction gets called is it when the caller function makes a call like this myFunciton.then ()? Can I say the first one triggers upon myFunction being resolved and second call back function is called upon failure of the myFunction?
myFunciton: function() {
const myPromise = myService.loadData(oParams);
myPromise.then(() => {
//do something
}, () => {
//do something else
});
return myPromise;
}
Promises are a state machine with several potential states: pending(The initial state), fulfilled, and rejected.
When you create a new promise you provide a callback that accepts two parameters both functions resolve and reject respectively. resolve to enter a state of fulfilled, reject to enter a state of rejected, and if the code your promise wraps throws an exception the promise will also enter a state of rejected. Upon being either resolved or rejected your promise will store the returned value for subsequent resolutions.
Now whenever you call myPromise.then, myPromise.catch, or providing a call back function. The promise internally checks it's state.
If the promise is pending, it will queue your handlers, and when a call to reject, resolve, or an exception is thrown it will iterate through the queued handlers and call the appropriate handler(Depending on whether it was resolved or rejected).
Now if the promise is already fulfilled or rejected, the promise will call the appropriate handler asynchronously.
Let's look at your code:
myFunction: function() {
const myPromise = myService.loadData(oParams);
// handlers are queued if myPromise is pending
// function passed to then is called asynchronously if resolved
// callback will be called asynchronously if rejected
myPromise.then(() => {
//do something
}, () => {
//do something else
});
return myPromise;
}
Now your question on when your callbacks will be called.
// This will trigger the execution of myService.loadData
// As pointed out in the comments above your callbacks will either be queued, or
// called asynchronously.
// The value of myPromiseResult will always be a promise(pending, resolved, or // rejected)
const myPromiseResult = myFunction();
// Here's the cool part, since promises are essentially a state machine
// every subsequent callback will yield the same result
myPromiseResult.then(() => {
// if the callback pass to myPromise.then is called within myFunction
// this will be called as well, and if you were passing a result
// it would have the same result as well
}, () => {
// if the error callback pass to myPromise within myFunction was called
// then this will be called as well, and as mentioned above would have
// been passed the same result as well.
});
With that code, the first promise that will be resolved will be the one inside "myFunciton" function. Then, if you used something like myFunciton.then(), it will be resolved in second place.
I hope i could help you.
I am sure that all the codes below, except resolve(Promise.resolve(p2)), are synchronous.
So I expect the result is p2 first since the p2.then run first. However p1 comes out first in console.
MDN has nothing related to the question.
Does the spec has some details? Can someone make it clear step by step what happens in resolving a promise?
Chrome v60.0.3112.113
My code is:
var p1 = new Promise(function(resolve, reject){
resolve("p1");
});
var p2 = new Promise(function(resolve, reject){
//resolve("p2");
var tempP = Promise.resolve("p2"); // for better description in discussion
resolve(tempP);
});
p2.then(function(value){
console.log(value)
})
p1.then(function(value){
console.log(value);
});
I am sure that all the codes below, except resolve(Promise.resolve(p2)), are synchronous.
No. then callbacks are never called synchronously, they're always asynchronous (and that's good). That means their relative order is indeterminate, and depends on when the respective promise was fulfilled. If you ever care about the order of callbacks, make it explicit by chaining the promises onto each other.
The order of fulfillment in your example depends on the value that you resolved the promises with. Notice that the new Promise callback and therefore your resolve are synchronous, in both p1 and p2. Every resolution is put into a queue - at least with native ES6 promises that you appear to be using. The difference is that your p2 is resolved with Promise.resolve("p2"), which will resolve p2 with the result of that other promise - which is put back onto the queue again. Therefore the fulfillment of p1 happens first, and the callback is called before the fulfillment callback of p2.
So what happens step-by-step is
The new Promise calls the constructor callback, which in turn
resolves the new promise with the value "p1" - fulfilling it
The new Promise returns and the value is assigned to p1.
The new Promise calls the constructor callback, which in turn
constructs another promise fulfilled with the value "p2"
and resolves the new promise with it - which adds another resolve as a callback for when that promise completes
The inner promise schedules that callback as it is already is fulfilled
The new Promise returns and the value is assigned to p2.
The p2.then is called and registers the fulfillment callback
The p1.then is called and schedules the fulfillment callback, as p1 is already fulfilled
After that, asynchronously:
the inner promise's callback is called and resolves p2 with the value "p2 - fulfilling it and scheduling its registered callbacks
the p1 callback is called and logs "p1"
the p2 callback is called and logs "p2"
This is the expected behavior.
Promise.resolve() returns a promise which is guaranteed to be asynchronous. So the value it returns will always resolve at the earliest on the next event loop after it is called. So in this case what happens is:
P2 returns a promise
P1 returns a promise
Next loop
P2 calls then() which resolves to a new promise that's scheduled for the next loop
P1 calls then() callback which resolves to a value which is printed
Next loop
P2's returned promise resolves and is printed
Both p1 and p2 are async, as you are creating a Promise.
New Promise() creates a new promise, and once it is created the following code is executed, but execution inside the Promise is done later (or at the same time; async).
p2.then is not executed before p1.then. The .then function is executed, once the promise resolves, and p1 resolves before p2
You code above :
var p2 = new Promise(function(resolve, reject){
resolve(Promise.resolve("p2"));
});
Is equivalent to doing :
var p2 = new Promise(function(resolve, reject) {
resolve(new Promise(function(resolve1, reject1) {
resolve1("p2");
}));
});
Which creates a new promise that is although immediately resolved, will be executed at the end of the call queue.
I was reading this article on promises http://www.html5rocks.com/en/tutorials/es6/promises/ In which he mentions the following point
"If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called, even though the event took place earlier"
I'm not clear about this point. My Question here is,if a promise had already succeeded and later at some point if i add a callback ,how can this callback execute even though the event took place earlier
Please explain
Thanks
Sahithi
The promise knows whether it was resolved or rejected. So if you attach another event handler to it, it will call it appropriately.
For example:
function myFunc(){ return Promise.resolve();}
var myPromise = myFunc();
myPromise.then(function(){console.log('I resolved.');});
myPromise.then(function(){console.log('Me too!');});
Would result in:
I resolved.
Me too!
When you call .then() on a promise, it has one of three possible things to do depending upon whether the promise is already resolved, rejected or still pending.
If the promise is currently pending (not resolved or rejected), it can queue the passed-in .then() handlers for later use when the promise is actually resolved or rejected.
It can see that the promise is already resolved so it can schedule the resolveHandler that was passed in to run as soon as the stack unwinds
It can see that the promise is already rejected so it can schedule the rejectHandler that was passed in to run as soon as the stack unwinds
Imagine this pseudo code to illustrate:
Promise.prototype.then = function(resolveHandler, rejectHandler) {
var self = this;
if (this._promiseState === "pending") {
// promise is not yet resolved or rejected so
// just queue the .then handlers for later use
this._handlers.push({resolve: resolvehandler, reject: rejectHandler});
} else if (this._promiseState === "resolved") {
// already resolved, schedule the resolve handler to run
// immediately after stack unwinds
if (resolveHandler) {
setImmediate(function() {
var p = resolveHandler(self._resolvedValue);
// further processing
});
}
} else {
// already rejected, schedule the reject handler to run
// immediately after stack unwindws
if (rejectHandler) {
setImmediate(function() {
var p = rejectHandler(self._rejectReason);
// further processing
});
}
}
// more code here that eventually returns a new promise
}
If I understood your question correctly, this basically means that you can run a promise and after running it, set the callback.
In event-oriented programming, you must first set the event callback, otherwise if triggered it'll never do the proper callback.
With promises, you can run a promise someFunc() and later add the callbacks, regardless of when the promise is fulfilled in runtime.