Promise 是什么
Promise 是异步编程的一种解决方案,比传统的回调函数和事件更加合理易用。它是一个容器,里面保存着某个未来才会结束的事件的结果,也是一个可以获取异步操作消息的对象。举个例子,如果想要使用 Promise API 异步调用一个远程的服务器,需要创建一个代表数据将会在未来由 Web 服务返回的 Promise 对象,目前数据还不可用,当请求完成并从服务器返回时数据将变为可用数据,在这个过程中,Promise 对象扮演一个数据的代理角色。在 Promise 对象上绑定一个回调函数,数据变得可用时这个回调函数将会被调用。
Promises/A+规范
Promise 是一个拥有 then 方法的对象或函数,并且其当前状态必须为一下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
- 等待态(Pending):可以迁移至执行态或拒绝态
- 执行态(Fulfilled):不能迁移至其他任何状态,必须拥有一个不可变的终值
- 拒绝态(Rejected):不能迁移至其他任何状态,必须拥有一个不可变的拒绝原因
一个 Promise 必须提供一个 then 方法以访问其当前值、终值和拒绝原因。
Promise 的 then 方法接收两个参数:
1
| promise.then(onFilfilled, onRejected);
|
onFulfilled 和 onRejected 都是可选参数。
- 如果 onFulfilled 不是函数,其必须被忽略
- 如果 onRejected 不是函数,其必须被忽略
onFulfilled 特性
如果 onFulfilled 是函数:
- 当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值
- 在 promise 执行结束前其不可被调用
- 其调用次数不可超过一次
onRejected 特性
如果 onRejected 是函数:
- 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因
- 在 promise 被拒绝执行前其不可被调用
- 其调用次数不可超过一次
调用时机
onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用
调用要求
onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)
多次调用
then 方法可以被同一个 promise 调用多次
- 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
- 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
返回
then 方法必须返回一个 promise 对象
1
| promise2 = promise1.then(onFulfilled, onRejected);
|
- 如果 onFulfilled 或者 onRejected 返回一个值 x,则运行下面的 Promise 解决过程:[Resolve]
- 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
- 如果 onFulfilled 不是函数且 promise1 成功执行,promise2 必须成功执行并返回相同的值
- 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的拒因
如何实现
状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var PENDING = 0; var FULFILLED = 1; var REJECTED = 2;
function Promise() { var state = PENDING;
var value = null;
var handlers = []; }
|
状态变迁
仅支持两种状态变迁, fulfill 和 reject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
function Promise() {
function fulfill(result) { state = FULFILLED; value = result; }
function reject(error) { state = REJECTED; value = error; } }
|
fulfill 和 reject 方法较为底层,通常更高级的 resolve 方法开放给外部。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
function Promise() {
function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject); return; } fulfill(result); } catch (e) { reject(e); } } }
|
resolve 方法可以接受一个普通值或者另一个 promise 作为参数,如果接受一个 promise 作为参数,等待其完成。 promise 不允许被另一个 promise fulfill ,所以需要开放 resolve 方法。 resolve 方法依赖一些帮助方法定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
function getThen(value) { var t = typeof value; if (value && (t === "object" || t === "function")) { var then = value.then; if (typeof then === "function") { return then; } } return null; }
function doResolve(fn, onFulfilled, onRejected) { var done = false; try { fn( function (value) { if (done) return; done = true; onFulfilled(value); }, function (reason) { if (done) return; done = true; onRejected(reason); } ); } catch (ex) { if (done) return; done = true; onRejected(ex); } }
|
这里 resolve 和 doResolve 之间的递归很巧妙,用来处理 promise 的层层嵌套( promise 的 value 是一个 promise )。
构造器
1 2 3 4 5 6
|
function Promise(fn) { doResolve(fn, resolve, reject); }
|
.done 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function Promise(fn) {
function handle(handler) { if (state === PENDING) { handlers.push(handler); } else { if (state === FULFILLED && typeof handler.onFulfilled === "function") { handler.onFulfilled(value); } if (state === REJECTED && typeof handler.onRejected === "function") { handler.onRejected(value); } } }
this.done = function (onFulfilled, onRejected) { setTimeout(function () { handle({ onFulfilled: onFulfilled, onRejected: onRejected }); }, 0); }; }
|
.then 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function Promise(fn) { this.then = function (onFulfilled, onRejected) { var self = this; return new Promise(function (resolve, reject) { return self.done( function (result) { if (typeof onFulfilled === "function") { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }, function (error) { if (typeof onRejected === "function") { try { return resolve(onRejected(error)); } catch (ex) { return reject(ex); } } else { return reject(error); } } ); }); }; }
|
参考资料
- Node.js 最新技术栈之 Promise 篇
- Promises/A+
- Promise 迷你书