What is Promise
Official definition: A Promise is an object representing the eventual completion or failure of an asynchronous operation. To be brief, it makes possible to schedule callbacks elegantly, like an assembly line.myPromise.then(action1).then(action2).then(action3).catch(handleRejection)
A Promise
could be in one of three states:
- pending: initial state, neither fulfilled or rejected.
- fulfilled: operation was completed successfully.
- rejected: operation failed.
How Promise works
Constructor
Syntax:
1 | new Promise(executor) |
Demo:
1 | // new Promise(executor) |
At first I was confused since it appears that resolve
passed to constructor has some association with Promise.then
method. But this is wrong: they own no ties when executing. resolve
in constructor is immediately called(sync) when creating a new Promise
object, whereas handler passed to Promise.then
might be called later(async). executor
, or resolve
/reject
, is used to set the state of Promise
, whereas the handler passed to Promise.then
will react to the state of Promise
[1]
Promise.then() and Chaining
Syntax:
1 | p.then(onFulfilled[, onRejected]); |
Demo:
1 | const promise1 = new Promise((resolve, reject) => { |
Promise.then()
is the most important part. It takes up two functions. onFulfilled
will be called when the Promise
is fulfilled, take the fulfillment value
from the Promise
, and return a new Promise
which can be chained. onRejected
will be called if Promise
is rejected. In the demo, string Success!
is the fulfillment value
of promise1
, and is printed when onFulfilled
is called in .then()
. For more details, see MDN docs.
Chaining is one essential usage of Promise
. See an example:
1 | p.then(action1).then(action2).then(action3).then(action4).catch(errHandler); |
The promises of a chain are initialized as a first-in-first-out queue: tasks enqueued first are excuted first. When a promise/task is handled, it gets popped, and a new generated promise gets enqueued.
Promise.resolve()
Syntax:
1 | Promise.resolve(value); |
Demo:
1 | Promise.resolve("Success").then( |
Promise.resolve()
returns a resolved Promise
with given value. If value is a promise, it will be returned. If value is a “thenable” object, the returned promise will keep the “thenable”. Otherwise return a promise fulfilled with the value. MDN docs gives more details.
Implementation
Now let’s implement one simple Promise
. Do not intent to design a perfect one which strictly follow the Promises/A+ standard, but aim for better interpretation.
Constructor
Constructor receives parameter executor
, and executor
receives resolve/reject
function which will be immediately executed. reolve/reject
will change the state of promise. onFulfilledQueue/onRejectedQueue
stores asynchronous onFulfilled/onRejected
operations from Promise.prototype.then()
as promise is in pending state, and will be executed as long as promise’s state become fulfilled/rejected.
1 | const PENDING = "pending"; |
Promise.prototype.then()
Promise.prototype.then()
appears more complicated. It is a state machine, returning a new promise given current promise’s state.
1 | Promise.prototype.then = function (onFulfilled, onRejected) { |
a. The two lines deal with case when onFulfilled/onRejected
are not functions. If an object gets passed, Promise.ptorotype.then()
will simple return this object.
1 | onFulfilled = |
b. Here setTimeout()
mimics microtask. For how promise microtask works, see here
c. As a promise keep pending state, all handlers(tasks) passed to .then()
need to be queued. Once the state changed, tasks in onFulFilledQueue
and onRejectedQueue
are executed in order.
Promise Resolution Procedure
resolvePromise()
in Promise.prototype.then()
illustrates the promise resolution procedure that is defined here. The code in this part is mainly from a great promise implementation. flag
ensures the resolution procedure only run once.
1 | var resolvePromise = function (promise2, x, resolve, reject) { |
Conclusion
This post takes me two days. Previously no idea came to me of diving into details of Promise, until last week optimizations were required, then I realized my poverty on Javascript’s asynchronous programming. This post mainly explains the mechanism of Promise
, and implements one according Promises/A+ standard. Here is complete code, please install tester first npm install -g promises-aplus-tests
, then run promises-aplus-tests promise.js
.
Relative Readings
Using Promises - Javascript MDN
Promise 的源码实现(完美符合 Promise/A+规范)
[[1]](#id01)[stackoverflow](https://stackoverflow.com/questions/31324110/why-does-the-promise-constructor-require-a-function-that-calls-resolve-when-co)