Suppose I have the following Promise:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
const result = doSomeWork();
setTimeout(() => {
resolve(result);
}), 100);
});
}
At which point in time is doSomeWork() called? Is it immediately after or as the Promise is constructed? If not, is there something additional I need to do explicitly to make sure the body of the Promise is run?
Immediately, yes, by specification.
From the MDN:
The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object)
This is defined in the ECMAScript specification (of course, it's harder to read...) here (Step 9 as of this edit, showing that the executor is called synchronously):
Let completion be Completion(Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
(my emphasis)
This guarantee may be important, for example when you're preparing several promises you then pass to all or race, or when your executors have synchronous side effects.
You can see from below the body is executed immediately just by putting synchronous code in the body rather than asynchronous:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous();
console.log("b");
The result shows the promise body is executed immediately (before 'b' is printed).
The result of the Promise is retained, to be released to a 'then' call for example:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous().then(function(pr) {
console.log("c:" + pr);
});
console.log("b");
Result:
a
b
c:promise result
Same deal with asynchronous code in the body except the indeterminate delay before the promise is fulfilled and 'then' can be called (point c). So a and b would be printed as soon as doSomethingAsynchronous() returns but c appears only when the promise is fulfilled ('resolve' is called).
What looks odd on the surface once the call to then is added, is that b is printed before c even when everything is synchronous.
Surely a would print, then c and finally b?
The reason why a, b and c are printed in that order is because no matter whether code in the body is async or sync, the then method is always called asynchronously by the Promise.
In my mind, I imagine the then method being invoked by something like setTimeout(()=>{then(pr)},0) in the Promise once resolve is called. I.e. the current execution path must complete before the function passed to then will be executed.
Not obvious from the Promise specification why it does this?
My guess is it ensures consistent behavior regarding when then is called (always after current execution thread finishes) which is presumably to allow multiple Promises to be stacked/chained together before kicking off all the then calls in succession.
Yes, when you construct a Promise the first parameter gets executed immediately.
In general, you wouldn't really use a promise in the way you did, as with your current implementation, it would still be synchronous.
You would rather implement it with a timeout, or call the resolve function as part of an ajax callback
function doSomethingAsynchronous() {
return new Promise((resolve) => {
setTimeout(function() {
const result = doSomeWork();
resolve(result);
}, 0);
});
}
The setTimeout method would then call the function at the next possible moment the event queue is free
From the EcmaScript specification
The executor function is executed immediately by the Promise
implementation, passing resolve and reject functions (the executor is
called before the Promise constructor even returns the created object)
Consider the following code:
let asyncTaskCompleted = true
const executorFunction = (resolve, reject) => {
console.log("This line will be printed as soon as we declare the promise");
if (asyncTaskCompleted) {
resolve("Pass resolved Value here");
} else {
reject("Pass reject reason here");
}
}
const myPromise = new Promise(executorFunction)
When we execute the above code, executorFunction will be called automatically as soon as we declare the Promise, without us having to explicitly invoke it.
Related
Suppose I have the following Promise:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
const result = doSomeWork();
setTimeout(() => {
resolve(result);
}), 100);
});
}
At which point in time is doSomeWork() called? Is it immediately after or as the Promise is constructed? If not, is there something additional I need to do explicitly to make sure the body of the Promise is run?
Immediately, yes, by specification.
From the MDN:
The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object)
This is defined in the ECMAScript specification (of course, it's harder to read...) here (Step 9 as of this edit, showing that the executor is called synchronously):
Let completion be Completion(Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
(my emphasis)
This guarantee may be important, for example when you're preparing several promises you then pass to all or race, or when your executors have synchronous side effects.
You can see from below the body is executed immediately just by putting synchronous code in the body rather than asynchronous:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous();
console.log("b");
The result shows the promise body is executed immediately (before 'b' is printed).
The result of the Promise is retained, to be released to a 'then' call for example:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous().then(function(pr) {
console.log("c:" + pr);
});
console.log("b");
Result:
a
b
c:promise result
Same deal with asynchronous code in the body except the indeterminate delay before the promise is fulfilled and 'then' can be called (point c). So a and b would be printed as soon as doSomethingAsynchronous() returns but c appears only when the promise is fulfilled ('resolve' is called).
What looks odd on the surface once the call to then is added, is that b is printed before c even when everything is synchronous.
Surely a would print, then c and finally b?
The reason why a, b and c are printed in that order is because no matter whether code in the body is async or sync, the then method is always called asynchronously by the Promise.
In my mind, I imagine the then method being invoked by something like setTimeout(()=>{then(pr)},0) in the Promise once resolve is called. I.e. the current execution path must complete before the function passed to then will be executed.
Not obvious from the Promise specification why it does this?
My guess is it ensures consistent behavior regarding when then is called (always after current execution thread finishes) which is presumably to allow multiple Promises to be stacked/chained together before kicking off all the then calls in succession.
Yes, when you construct a Promise the first parameter gets executed immediately.
In general, you wouldn't really use a promise in the way you did, as with your current implementation, it would still be synchronous.
You would rather implement it with a timeout, or call the resolve function as part of an ajax callback
function doSomethingAsynchronous() {
return new Promise((resolve) => {
setTimeout(function() {
const result = doSomeWork();
resolve(result);
}, 0);
});
}
The setTimeout method would then call the function at the next possible moment the event queue is free
From the EcmaScript specification
The executor function is executed immediately by the Promise
implementation, passing resolve and reject functions (the executor is
called before the Promise constructor even returns the created object)
Consider the following code:
let asyncTaskCompleted = true
const executorFunction = (resolve, reject) => {
console.log("This line will be printed as soon as we declare the promise");
if (asyncTaskCompleted) {
resolve("Pass resolved Value here");
} else {
reject("Pass reject reason here");
}
}
const myPromise = new Promise(executorFunction)
When we execute the above code, executorFunction will be called automatically as soon as we declare the Promise, without us having to explicitly invoke it.
I think one principle I take so far is:
A promise is a thenable object, and so it takes the message then, or in other words, some code can invoke the then method on this object, which is part of the interface, with a fulfillment handler, which is "the next step to take", and a rejection handler, which is "the next step to take if it didn't work out." It is usually good to return a new promise in the fulfillment handler, so that other code can "chain" on it, which is saying, "I will also tell you the next step of action, and the next step of action if you fail, so call one of them when you are done."
However, on a JavaScript.info Promise blog page, it says the fulfillment handler can return any "thenable" object (that means a promise-like object), but this thenable object's interface is
.then(resolve, reject)
which is different from the usual code, because if a fulfillment handler returns a new promise, this thenable object has the interface
.then(fulfillmentHandler, rejectionHandler)
So the code on that page actually gets a resolve and call resolve(someValue). If fulfillmentHandler is not just another name for resolve, then why is this thenable different?
The thenable code on that page:
class Thenable {
constructor(num) {
this.num = num;
}
then(resolve, reject) {
alert(resolve); // function() { native code }
// resolve with this.num*2 after the 1 second
setTimeout(() => resolve(this.num * 2), 1000); // (**)
}
}
new Promise(resolve => resolve(1))
.then(result => {
return new Thenable(result); // (*)
})
.then(alert); // shows 2 after 1000ms
A thenable is any object containing a method whose identifier is then.
What follows is the simplest thenable one could write. When given to a Promise.resolve call, a thenable object is coerced into a pending Promise object:
const thenable = {
then() {}, // then does nothing, returns undefined
};
const p = Promise.resolve(thenable);
console.log(p); // Promise { <pending> }
p.then((value) => {
console.log(value); // will never run
}).catch((reason) => {
console.log(reason); // will never run
});
The point of writing a thenable is for it to get coerced into a promise at some point in our code. But a promise that never settles isn't useful. The example above has a similar outcome to:
const p = new Promise(() => {}); //executor does nothing, returns undefined
console.log({ p }); // Promise { <pending> }
p.then((value) => {
console.log(value); // will never run
}).catch((reason) => {
console.log(reason); // will never run
});
When coercing it to a promise, JavaScript treats the thenable's then method as the executor in a Promise constructor (though from my testing in Node it appears that JS pushes a new task on the stack for an executor, while for a thenable's then it enqueues a microtask).
A thenable's then method is NOT to be seen as equivalent to promise's then method, which is Promise.prototype.then.
Promise.prototype.then is a built-in method. Therefore it's already implemented and we just call it, passing one or two callback functions as parameters:
// Let's write some callback functions...
const onFulfilled = (value) => {
// our code
};
const onRejected = (reason) => {
// our code
};
Promise.resolve(5).then(onFulfilled, onRejected); // ... and pass both to a call to then
The executor callback parameter of a Promise constructor, on the other hand, is not built-in. We must implement it ourselves:
// Let's write an executor function...
const executor = (resolve, reject) => {
// our asynchronous code with calls to callbacks resolve and/or reject
};
const p = new Promise(executor); // ... and pass it to a Promise constructor
/*
The constructor will create a new pending promise,
call our executor passing the new promise's built-in resolve & reject functions
as first and second parameters, then return the promise.
Whenever the code inside our executor runs (asynchronously if we'd like), it'll have
said promise's resolve & reject methods at its disposal,
in order to communicate that they must respectivelly resolve or reject.
*/
A useful thenable
Now for a thenable that actually does something. In this example, Promise.resolve coerces the thenable into a promise:
const usefulThenable = {
// then method written just like an executor, which will run when the thenable is
// coerced into a promise
then(resolve, reject) {
setTimeout(() => {
const grade = Math.floor(Math.random() * 11)
resolve(`You got a ${grade}`)
}, 1000)
},
}
// Promise.resolve coerces the thenable into a promise
let p = Promise.resolve(usefulThenable)
// DO NOT CONFUSE the then() call below with the thenable's then.
// We NEVER call a thenable's then. Also p is not a thenable, anyway. It's a promise.
p.then(() => {
console.log(p) // Promise { 'You got a 9' }
})
console.log(p) // Promise { <pending> }
Likewise, the await operator also coerces a thenable into a promise
console.log('global code has control')
const usefulThenable = {
// then() will be enqueued as a microtask when the thenable is coerced
// into a promise
then(resolve, reject) {
console.log("MICROTASK: usefulThenable's then has control")
setTimeout(() => {
console.log('TASK: timeout handler has control')
const grade = Math.floor(Math.random() * 11)
resolve(`You got a ${grade}`)
}, 1000)
},
}
// Immediately Invoked Function Expression
let p = (async () => {
console.log('async function has control')
const result = await usefulThenable //coerces the thenable into a promise
console.log('async function has control again')
console.log(`async function returning '${result}' implicitly wrapped in a Promise.resolve() call`)
return result
})()
console.log('global code has control again')
console.log({ p }) // Promise { <pending> }
p.then(() => {
console.log('MICROTASK:', { p }) // Promise { 'You got a 10' }
})
console.log('global code completed execution')
The output:
/*
global code has control
async function has control
global code has control again
{ p: Promise { <pending> } }
global code completed execution
MICROTASK: usefulThenable's then has control
TASK: timeout handler has control
async function has control again
async function returning 'You got a 10' implicitly wrapped in a Promise.resolve() call
MICROTASK: { p: Promise { 'You got a 10' } }
*/
TL;DR: Always write the thenable's then method as you would the executor parameter of a Promise constructor.
In
let p2 = p1.then( onfulfilled, onrejected)
where p1 is a Promise object, the then call on p1 returns a promise p2 and records 4 values in lists held internally by p1:
the value of onfulfilled,
the value of the resolve function passed to the executor when creating p2 - let's call it resolve2,
the value of onrejected,
the value of the reject function passed to the executor when creating p2 - let's call it reject2.
1. and 3. have default values such that if omitted they pass fulfilled values of p1 on to p2, or reject p2 with the rejection reason of p1 respectively.
2. or 4. (the resolve and reject functions for p2) are held internally and are not accessible from user JavaScript.
Now let's assume that p1 is (or has been) fullfilled by calling the resolve function passed to its executor with a non thenable value. Native code will now search for existing onfulfilled handlers of p1, or process new ones added:
Each onfulfilled handler (1 above) is executed from native code inside a try/catch block and its return value monitored. If the return value, call it v1, is non-thenable, resolve for p2 is called with v1 as argument and processing continues down the chain.
If the onfulfilled handler throws, p2 is rejected (by calling 4 above) with the error value thrown.
If the onfulfilled handler returns a thenable (promise or promise like object), let's call it pObject, pObject needs to be set up pass on its settled state and value to p2 above.
This is achieved by calling
pObject.then( resolve2, reject2)
so if pObject fulfills, its non-thenable success value is used to resolve p2, and if it rejects its rejection value is used to reject p2.
The blog post defines its thenable's then method using parameter names based on how it is being used in the blog example (to resolve or reject a promise previously returned by a call to then on a native promise). Native promise resolve and reject functions are written in native code, which explains the first alert message.
After writing down the whole explanation, the short answer is: it is because the JS promise system passed in a resolve and reject as the fulfillmentHandler and rejectionHandler. The desired fulfillmentHandler in this case is a resolve.
When we have the code
new Promise(function(resolve, reject) {
// ...
}).then(function() {
return new Promise(function(resolve, reject) {
// ...
});
}).then(function() { ...
We can write the same logic, using
let p1 = new Promise(function(resolve, reject) {
// ...
});
let p2 = p1.then(function() {
let pLittle = new Promise(function(resolve, reject) {
// ...
resolve(vLittle);
});
return pLittle;
});
The act of returning pLittle means: I am returning a promise, a thenable, pLittle. Now as soon as the receiver gets this pLittle, make sure that when I resolve pLittle with value vLittle, your goal is to immediately resolve p2 also with vLittle, so the chainable action can go on.
How does it do it?
It probably has some code like:
pLittle.then(function(vLittle) { // ** Our goal **
// somehow the code can get p2Resolve
p2Resolve(vLittle);
});
The code above says: when pLittle is resolved with vLittle, the next action is to resolve p2 with the same value.
So somehow the system can get p2Resolve, but inside the system or "blackbox", the function above
function(vLittle) {
// somehow the code can get p2Resolve
p2Resolve(vLittle);
}
is probably p2Resolve (this is mainly a guess, as it explains why everything works). So the system does
pLittle.then(p2Resolve);
Remember that
pLittle.then(fn)
means
passing the resolved value of pLittle to fn and invoke fn, so
pLittle.then(p2Resolve);
is the same as
pLittle.then(function(vLittle) {
p2Resolve(vLittle)
});
which is exactly the same as ** Our goal** above.
What it means is, the system passes in a "resolve", as a fulfillment handler. So at this exact moment, the fulfillment handler and the resolve is the same thing.
Note that in the Thenable code in the original question, it does
return new Thenable(result);
this Thenable is not a promise, and you can't resolve it, but since it is not a promise object, that means that promise (like p2) is immediately resolved as a rule of what is being returned, and that's why the then(p2Resolve) is immediately called.
So I think this count on the fact that, the internal implementation of ES6 Promise passes the p2Resolve into then() as the first argument, and that's why we can implement any thenable that takes the first argument resolve and just invoke resolve(v).
I think the ES6 specification a lot of time writes out the exact implementation, so we may somehow work with that. If any JavaScript engine works slightly differently, then the results can change. I think in the old days, we were told that we are not supposed to know what happens inside the blackbox and should not count on how it work -- we should only know the interface. So it is still best not to return a thenable that has the interface then(resolve, reject), but to return a new and authentic promise object that uses the interface then(fulfillmentHandler, rejectionHandler).
I've tried to understand Promise
from google source, and haven't found how it execute code asynchronously.
My understanding of asynchronous function is that code below it can be resolved at a time before it.
For example:
setTimeout(()=>{console.log("in")}, 5000);
console.log("out");
// output:
// out
// in
The second line fufilled before the first line , so I think setTimeout is an asynchronous tech. But see this code of Promise:
let p = new Promise((resolve, reject)=>{console.log('in'); resolve(1);});
console.log("out");
//in
//out
This code block is actually excuted line by line, if console.log('in'); is a time-consuming operation, the second line will be blocked until it's resolved.
We usually use Promise like this:
(new Promise(function1)).then(function2).then(function3)
Does this mean: Promise is just used to promise that function2 is executed after function1, it's not a tech to realize asynchronous ,but a method to realize synchronous (function1, function2, function3 are executed sequently).
A promise is just a way to describe a value that does not exist yet, but will arrive later. You can attach .then handlers to it, to get notified if that happens.
Does this mean: Promise is just used to promise that function2 is executed after function1?
Yes exactly, even if function1 returns it's value asynchronously (through a Promise), function2 will run only if that value is present.
it's not a tech to realize 'asynchronous' but a method to realize 'synchronous' [execution] ?
Not really. It makes little sense to wrap a value that already exists into a promise. It makes sense to wrap a callback that will call back "asynchronously" into a promise. That said, the Promise itself does not indicate wether the value it resolves to was retrieved in a synchronous or asynchronous maner.
function retrieveStuffAsynchronously() {
// direclty returns a Promise, which will then resolve with the retrieved value somewhen:
return new Promise((resolve, reject) => {
// directly executes this, the async action gets started below:
setTimeout(() => { // the first async code, this gets executed somewhen
resolve("the value"); // resolves asynchronously
}, 1000);
});
}
console.log(retrieveStuffAsynchronously()); // does return a promise immeadiately, however that promise is still pending
retrieveStuffAsynchronously().then(console.log);
Sidenote: However, Promises are guaranteed to resolve asynchronously:
const promise = new Promise((resolve, reject)=>{
console.log('one');
resolve('three');
});
promise.then(console.log); // guaranteed to be called asynchronously (not now)
console.log("two");
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.
Suppose I have the following Promise:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
const result = doSomeWork();
setTimeout(() => {
resolve(result);
}), 100);
});
}
At which point in time is doSomeWork() called? Is it immediately after or as the Promise is constructed? If not, is there something additional I need to do explicitly to make sure the body of the Promise is run?
Immediately, yes, by specification.
From the MDN:
The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object)
This is defined in the ECMAScript specification (of course, it's harder to read...) here (Step 9 as of this edit, showing that the executor is called synchronously):
Let completion be Completion(Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
(my emphasis)
This guarantee may be important, for example when you're preparing several promises you then pass to all or race, or when your executors have synchronous side effects.
You can see from below the body is executed immediately just by putting synchronous code in the body rather than asynchronous:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous();
console.log("b");
The result shows the promise body is executed immediately (before 'b' is printed).
The result of the Promise is retained, to be released to a 'then' call for example:
function doSomethingAsynchronous() {
return new Promise((resolve) => {
console.log("a");
resolve("promise result");
});
}
doSomethingAsynchronous().then(function(pr) {
console.log("c:" + pr);
});
console.log("b");
Result:
a
b
c:promise result
Same deal with asynchronous code in the body except the indeterminate delay before the promise is fulfilled and 'then' can be called (point c). So a and b would be printed as soon as doSomethingAsynchronous() returns but c appears only when the promise is fulfilled ('resolve' is called).
What looks odd on the surface once the call to then is added, is that b is printed before c even when everything is synchronous.
Surely a would print, then c and finally b?
The reason why a, b and c are printed in that order is because no matter whether code in the body is async or sync, the then method is always called asynchronously by the Promise.
In my mind, I imagine the then method being invoked by something like setTimeout(()=>{then(pr)},0) in the Promise once resolve is called. I.e. the current execution path must complete before the function passed to then will be executed.
Not obvious from the Promise specification why it does this?
My guess is it ensures consistent behavior regarding when then is called (always after current execution thread finishes) which is presumably to allow multiple Promises to be stacked/chained together before kicking off all the then calls in succession.
Yes, when you construct a Promise the first parameter gets executed immediately.
In general, you wouldn't really use a promise in the way you did, as with your current implementation, it would still be synchronous.
You would rather implement it with a timeout, or call the resolve function as part of an ajax callback
function doSomethingAsynchronous() {
return new Promise((resolve) => {
setTimeout(function() {
const result = doSomeWork();
resolve(result);
}, 0);
});
}
The setTimeout method would then call the function at the next possible moment the event queue is free
From the EcmaScript specification
The executor function is executed immediately by the Promise
implementation, passing resolve and reject functions (the executor is
called before the Promise constructor even returns the created object)
Consider the following code:
let asyncTaskCompleted = true
const executorFunction = (resolve, reject) => {
console.log("This line will be printed as soon as we declare the promise");
if (asyncTaskCompleted) {
resolve("Pass resolved Value here");
} else {
reject("Pass reject reason here");
}
}
const myPromise = new Promise(executorFunction)
When we execute the above code, executorFunction will be called automatically as soon as we declare the Promise, without us having to explicitly invoke it.