When we design a function that returns a promise, like this:
function getAsyncResult() {
// synchronous code 1
return new Promise(function (resolve, reject) {
// synchronous code 2
// asynchronous code
});
}
Does it make a difference whether we place our synchronous code before we create the resulting promise or at the beginning of the callback?
In other words, is it possible that there can be a delay between new Promise(...) and the call into its callback function?
To rephrase it again, is it possible that synchronous code 2 ever executes with a delay, and not immediately after synchronous code 1?
P.S. I am mostly interested in this with respect to ES6 Promise and Bluebird, although would be nice to know if other major libraries do it differently.
According to the ES6 spec, what it calls the "executor" (the callback passed to the constructor) is executed immediately. Therefore, an implementation which did not behave this way would not be conforming, and you can depend on it.
Therefore, you can put your code either before calling the constructor, or within the executor, and it should not make any difference in terms of execution timing (although as another answer pointed out, there will be differences in terms of what happens if the code throws).
Other implementations may vary, and some may not even provide the ES6-style promise constructor, choosing to build promises in some other way.
With ES6/compliant Promise, synchronous code 1 and synchronous code 2 will (barring an uncaught error) execute in that order, in the same event turn. However, there is a difference :
synchronous code 1: An uncaught error will throw (to the console) in the usual way.
synchronous code 2: An uncaught error will give rise to Promise rejection.
asynchronous code doesn't really exist, at least not at this level; only inner functions can execute later. You may call a function that returns a promise. Such a promise, p, may be used to resolve/reject the outer Promise (the one being constructed), without using .then(), using the syntax resolve(p), in the same way you would write resolve(value).
With a resolve(p) statement in place, if p was to reject, then the outer Promise would also reject even though its own revealed reject method is not called explicitly by user code.
Promise is invented to avert the phenomenon known as callback hell. It is nothing but a structured system where you can register your callbacks more neatly than creating a nexus of it right in the middle of your code. Except this there is no asynchronous magic happening in Promise.
Lets look at this
return new Promise(function (resolve, reject) {
// synchronous code 2
// asynchronous code
});
You are returning a promise which provide the facility to hook two functions (resolve and reject) which will be called (by you) after an asynchronous operation which will also be initiated by you inside the promise function.
This can be an input from the user, an ajax request etc - which you really don't know when is going to happen.
The execution of code inside your promise constructor happens immediately where you can start your asynchronous process (synchronous code 2) before reaching any other line of code.
If you really need to separate the linear execution of synchronous code 2 and asynchronous code, probably you can put the latter inside a setTimeout function. This way it is executed when the browser gets the next breathing space. But that kind of practice is little skewed in the face of the concept of Promise.
Absolutely no delay will happen: the code will be executed in the same stack, synchronously.
As a proof, you can run this snippet:
console.log('sync code before promise');
new Promise(function (resolve, reject) {
console.log('sync code in promise');
});
console.log('sync code after promise');
Result is before -> in -> after
Related
I know javascrip is a single thread application. I think to implement asynchronous programing it execute different part of a program synchronously.
In the case of promises it does not stop the execution to resolve the promises. It just execute the other part and my question is what happend when the promise resolves. It just stop the current execution and start the then part of the promise or execute the then part only after completing the current execution
No. The current queue of code will run before coming back to fulfill promises. This includes the 'then' method.
Promises use "continuation-passing style" ("CPS").
The node approach to CPS is that asynchronous functions accept callbacks. Like so:
const FS = require('fs')
FS.readFile( path, 'utf8', function callback(error, data) {
// FS.readFile will invoke this function with an error or the file contents
// once the read operation is complete
})
An explicit promise (i.e. not async/await), looks pretty similar:
const myPromise = new Promise(function callback(resolve, reject) {
// invoke the non-blocking thing, then use resolve or reject to pass something onward
} )
The callback function is a "continuation," and you provide that continuation to the
asynchronous function knowing that it will eventually be invoked with whatever is the result of the non-blocking task.
Promises often look similar, at least superficially. Promise polyfills (which are often not needed) literally work by using some hairy but non-magical CPS code, plus timeouts or events, to provide the same interface. I suspect that modern JS engines use some kind of lower-level mechanism that does not lean on CPS to wire the data into the "callback."
According to MDN:
The executor function is executed immediately by the Promise implementation, passing resolve and reject functions
What were the actual reasons for this decision?
Why promises are not lazy?
What were the actual reasons for this decision?
The revealing Promise constructor with the callback was just an improvement over the older deferred pattern. The callback was never meant to provide choice over the evaluation time, it is supposed to provide a scope with error handling for the resolver functions.
Why promises are not lazy?
Because promises represent the asynchronous result values, nothing more. They're kept simple, without featuring lazyness (and representing the whole computation, with methods to start/repeat/etc). You can trivially get that by using a function that returns a promise instead.
Promises are meant to provide continuations, and actual state of standard Promise object proposes the following pattern:
function doStuff() {
return new Promise((resolve, reject) => { // execution function
// Do stuff here
});
}
I would ask a question myself to understand why Promise's execution function is called immediatelly: where you would do the promised stuff?
Clearly, it's called immediatelly because you're making a promise that some stuff will be successfully or unsucessfully done, and that stuff should start to be processed as soon as you call the enclosing function to avoid confusion to the caller.
The point of a promise is to have something to return from a function that callers can attach their callbacks to rather than pass them in. The constructor is a red herring to answer "why", as it exists solely to wrap old callback-style code in an imperfect world.
All JS functions are synchronous, even those returning a promise (es8's async is syntactic sugar).
The Promise constructor executor function exists to provide unified error handling. Consider:
function foo() {
""(); // throws TypeError
return Promise(resolve => {
""(); // rejects promise with TypeError
});
}
Callers would need both try{ foo().catch(failed); } catch(e) { failed(e); } = Sucks.
So put all your synchronous code inside the executor function to unify errors for your callers. That's what it's for, which I think is your real question.
"Lazy" execution would defeat the purpose of unifying error handling of all your code.
Let's say I have a synchronous function like path.join(). I want to wrap it into a Promise because I want exceptions to be handled within catch() block.
If I wrap it like below, I do not get an exception in the Promise's .catch() block. So I have to use if to check the return value for whether it's an error or not and then call resolve or reject functions. Are there any other solutions?
var joinPaths = function(path1,path2) {
return new promise(function (resolve, reject) {
resolve(path.join(path1, path2));
});
};
It is unclear why you would wrap a synchronous operation in a promise as that just makes it more difficult to use and synchronous operations can already be used within promise chains just fine.
The only two places I've seen it useful to make a promise out of something synchronous are to start a promise chain where subsequent operations will be async or when you are branching and one result of the branch is async promise and the other is synchronous. Then, in that case, you want to just return a promise in both cases so the caller has a consistent async interface no matter which branch is taken. Or, this could also occur with different implementations of a common API, one implementation which is synchronous and the other asynchronous. The API would be designed with an asynchronous interface and the synchronous implementation would probably wrap itself in a promise to fulfill the asynchronous contract of the common API.
Other than that, you should generally not make synchronous things async because it just unnecessarily complicates using them.
The simplest way I know of to make it into a promise would be this:
Promise.resolve(path.join(path1, path2)).then(function(path) {
// use the result here
});
Per your comments, inside a .then() handler, exceptions are already captured by the promise infrastructure and turned into a rejected promise. So, if you had this:
someAsyncOp().then(function(value) {
// some other stuff
// something that causes an exception
throw new Error("timeout");
}).catch(function(err){
console.log(err); // will show timeout
});
Then, that exception is already mapped into a promise rejection for you. Of course, if you want to handle the exception inside of the .then() handler (not turn the promise into a rejection), then you can just use a traditional try/catch around your synchronous operation to catch a local exception (no different than any other synchronous code). But, if you want the promise to reject if there's an exception inside the .then() handler, then that is all done for you automatically (a very nice feature of promises).
Not sure if it's the best way but it works. I came to StackOverflow to check if there's a better way.
new Promise((resolve, reject) => {
try {
resolve(path.join());
} catch (err) {
reject(err);
}
})
Very quick way is to wrap prepend a function with async keyword. Any async function returns a Promise
const sum = async (a, b) => a + b;
sum(1, 2).then(value => console.log(value))
As I plunge into studying Promises, my understanding has halted on the following question that I do not find discussed (all I find are specific discussions of the Promise constructor, and the Promise 'then' function - but not a discussion that compares their design patterns).
1. The Promise constructor
From the MDN documentation, we have this use of the Promise constructor (with my comment added):
new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1
Function object with two arguments resolve and reject. The first
argument fulfills the promise, the second argument rejects it. We can
call these functions, once our operation is completed.
2. The then function
Moving on to the then function that can be called on a Promise object (which returns a new Promise object), we have the following function signature as described by the documentation (with my comments added):
p.then(onFulfilled, onRejected);
Chaining
Because the then method returns a Promise, you can easily chain then
calls.
var p2 = new Promise(function(resolve, reject) {
resolve(1); // <-- Stage 1 again
});
p2.then(function(value) {
console.log(value); // 1
return value + 1; // <-- Call this Stage 2
}).then(function(value) {
console.log(value); // 2
});
My question
From the above code snippet, it seems clear to me that the value passed to the resolve function in Stage 1 (in the second occurrence of resolve - beneath (2), above) is passed on to the next stage (the first then function that follows in the same code snippet). There is no return value at Stage 1. However, it is the return value at Stage 2 that is passed on to the next stage after that (the second then function).
Is this lack of correspondence between the design pattern for the creation of a Promise, and the use of the then function on an existing promise (which also returns a Promise), just a historical fluke (one requires calling a callback but returns nothing, and the other returns a value but does not call a callback)?
Or am I missing an underlying reason why the Promise constructor utilizes a different design pattern than the then function?
Bergi's answer is excellent, and has been very helpful to me. This answer is complementary to his. In order to visualize the relationship between the Promise() constructor and the then() method, I created this diagram. I hope it helps somebody... maybe even me, a few months months from now.
The main idea here is that the "executor" function passed to the Promise() constructor sets tasks in motion that will set the state of the promise; whereas the handlers you pass to then() will react to the state of the promise.
(Code examples adapted from Jake Archibald's classic tutorial.)
This is a highly simplified view of how things work, leaving out many important details. But I think if one can keep a grip on a good overview of the intended purpose, it will help avoid confusion when one gets into the details.
A couple of selected details
The executor is called immediately
One important detail is that the executor function passed to the Promise() constructor is called immediately (before the constructor returns the promise); whereas the handler functions passed to the then() method will not be called till later (if ever).
Bergi mentioned this, but I wanted to restate it without using the terms a/synchronously, which can be confused if you're not reading carefully: The distinction between a function calling something asynchronously vs. being called asynchronously is easy to gloss over in communication.
resolve() is not onFulfill()
One more detail I'd like to emphasize, because it confused me for a while, is that the resolve() and reject() callbacks passed to the Promise() constructor's executor function are not the callbacks later passed to the then() method. This seems obvious in retrospect, but the apparent connection had me spinning in circles for too long. There is definitely a connection, but it's a loose, dynamic one.
Instead, the resolve() and reject() callbacks are functions supplied by the "system", and are passed to the executor function by the Promise constructor when you create a promise. When the resolve() function is called, system code is executed that potentially changes the state of the promise and eventually leads to an onFulfilled() callback being called asynchronously. Don't think of calling resolve() as being a tight wrapper for calling onFulfill()!
There is no correspondence between the Promise constructor and the then method because they are two independent things, designed for different purposes.
The Promise constructor is only used for promisifying1 asynchronous functions. Indeed, as you say, it is built on invoking resolve/reject callbacks to asynchronously send values, and there are no return values in that case.
That the Promise constructor itself does take this "resolver" callback (to which it synchronously passes resolve and reject) is in fact an enhancement of the older deferred pattern, and bears no intended similarity to the then callbacks.
var p = new Promise(function(res, rej) { | var def = Promise.Deferred();
setTimeout(res, 100); | setTimeout(def.resolve, 100);
}); | var p = def.promise;
The then callbacks in contrast are classical asynchronous callbacks, with the additional feature that you can return from them. They are being invoked asynchronously to receive values.
p.then(function(val) { … });
To sum up the differences:
Promise is a constructor, while then is a method
Promise takes one callback, while then takes up to two
Promise invokes its callback synchronously, while then invokes its callbacks asynchronously
Promise always invokes its callback,
then might not invoke its callbacks (if the promise is not fulfilled/rejected)
Promise passes the capabilities to resolve/reject a promise to the callback,
then passes the result value / rejection reason of the promise it was called on
Promise invokes its callback for the purpose of executing side effects (call reject/resolve),
then invokes its callbacks for their result values (for chaining)
Yes, both do return promises, though they share that trait with many other functions (Promise.resolve, Promise.reject, fetch, …). In fact all of these are based on the same promise construction and resolve/reject capabilities that also the Promise constructor provides, though that's not their primary purpose. then basically offers the ability to attach onFulfilled/onRejected callbacks to an existing promise, which is rather diametral to the Promise constructor.
That both utilise callbacks is just coincidential - not a historical fluke, but rather coadaption of a language feature.
1: Ideally, you would never need this because all natively asynchronous APIs return promises
Inspired by the previous answers (I'll address the part that was most confusing to me):
The resolve and reject arguments in the Promise constructor are not functions you define. Think of them as hooks that you get to embed into your async operation code (usually you resolve with success response and reject with failure reason) , so that javascript has a way to eventually mark the Promise as Fulfilled or Rejected depending on the outcome of your async operation; once that happens, the appropriate function you defined in then(fun1, fun2) is triggered to consume the Promise (either fun1(success_response) or fun2(failure_reason), depending on whether the Promise is Fulfilled/Rejected). Since fun1 and fun2 are plain old javascript functions (they just happen to take the future outcome of your async operation as arguments), they return values (which can be undefined if you don't explicitly return).
Also see great articles by Mozilla:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
The whole point of the promise constructor executor function is to disseminate resolve and reject functions to non-promise-using code, to wrap it and convert it to use a promise. If you wanted to limit this to synchronous functions only, then yes, a return value from the function could have been used instead, but that would have been silly since the useful part is to disseminate the resolver and reject functions to code that actually runs later (way after the return), e.g. to callbacks passed in to some asynchronous API.
Here is the execution flow of Promise.
var p = new Promise((resolve, reject) =>{
console.log("1");
resolve("OK");
});
//The above code creates a promise and execustion starts immediately.
//it happens aynchronously. So the execution will not be blocked.
//Promise exustion will not wait for 'then' call on promise
console.log("2");
//The above line displays 2 on the console.
p.then((result)=>{
console.log("3");
console.log(result);
});
//The above code shoud not block execution. So it may print 4 first
// then 3
console.log("4");
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.