Javascript Promises-Dynamic Callbacks - javascript

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.

Related

Does the then() function return a promise reflecting the results of the previous promise?

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.

passing call back functions to promise.then()

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.

In Javascript, why evaluating a `then` method on a "resolved" Promise returns a "pending" Promise?

Following is the native Javascript code:
var first = Promise.resolve(1);
first.then((i)=>console.log(1))
When I inspect first in the console of Chrome, it shows its status is "resolved"
> first
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
However, when I inspect first.then((i)=>console.log(1)) in the console of Chrome, it shows that its status is "pending"
> first.then((i)=>console.log(1))
1
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
This looks confusing to me because I expected the first.then((i)=>console.log(1)) has the status of resolved as the callback within the then method has already been executed and finished.
Does anyone have ideas about this?
Promise.resolve().then(fn) returns a new promise that is not yet resolved, but will be resolved on the next tick after the current thread of execution unwinds and finishes.
Thus, if you immediately check to see if the returned promise is yet resolved, it will not be. But, if you wait until the next tick, it will then be resolved and the .then() handler function will be fired at that time.
To explain, each chained call to .then() returns a new promise that is chained to the prior one. And, per the Promise A+ specification, all .then() callback handlers are fired asynchronously after the stack has unwound (technically it says something like "when only platform code is on the stack").
So, .then() runs immediately and synchronously. It stores the callback(s) you pass it in the promise object and then those callbacks are actually called asynchronously some time in the future. If the promise is resolved quickly, then the fulfill callback will be called on the next "tick" when the current thread of execution has finished.
This stack unwinding and firing on the next tick is to make it so that .then() handlers are consistently firing asynchronously, not matter how quickly the promise is resolved. This allows the calling code to be written in one consistent manner when the promise is resolved immediately, in 1ms or in 20 minutes. They will all get resolved asynchronously some time in the future and thus the calling code can treat them all the same. The only thing that will be different is how long from now they are resolved or rejected.
For promises that confirm to Promise/A+ spec, for a then call of the form
promise.then(onFulfilled, onRejected)
there is a condition that
onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
So, assuming Chrome adheres to this spec for its promises, and only sets the (internal?) Promise status to resolved once the callbacks have been called, calling
Promise.resolve(1).then(onFulfilled, onRejected);
will always show an unresolved promise since the stack has not yet cleared and the callbacks not yet called. However,
var derived = Promise.resolve(1).then(onFulfilled, onRejected);
And then later, in the inspector calling
derived;
will show a resolved promise since the stack has cleared and the callbacks called. The call to
Promise.resolve(1);
is not subject to the constraint on having to wait for the stack to clear, and so returns an immediately resolved promise.

What happens if a promise completes before then is called?

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
});

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