[翻译]简单的实现一个Promise
英文原文为:https://www.promisejs.org/implementing/
1. 状态机
因为 promise 对象是一个状态机,所以我们首先应该定义将要用到的状态。
var PENDING = 0; var FULFILLED = 1; VAR REJECTED = 2; function Promise () { // 可以存储这些状态,PENDING、FULFILLED 或 REJECTED var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息 var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数 var handlers = []; }
2. 转换
接着,让我们来考虑一下两个可能发生的重要转换,fulfilling 和 rejecting:
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise () { // 可以存储这些状态,PENDING、FULFILLED 或 REJECTED var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息 var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数 var handlers = []; function fulfill (result) { state = FULFILLED; value = result; } function reject (error) { state = REJECTED; value = error; } }
这给了我们基础的低层转换,我们现在来考虑更高层的转换 resolve。
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise () { // 可以存储这些状态,PENDING、FULFILLED 或 REJECTED var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息 var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数 var handlers = []; function fulfill (result) { state = FULFILLED; value = result; } function reject (error) { state = REJECTED; value = error; } 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 对象还是一个简单值(plain value),如果是一个 promise 对象,如何等待他完成。
/** * 检查值是否是一个 Promise 对象, 如果他是, * 返回这个 Promise 对象的‘then’方法。 * * @param {Promise|Any} value * @return {Function|Null} */ 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; } /** * 潜在的解析函数,以确保 onFulfilled 和 onRejected 只执行其中的一个 */ 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); } }
3. 构造
我们现在有了完整的内部状态机,但我们还没有暴露出解决承诺(resolving promise)或观察它的方法。让我们从增加一个解决 promise 的方法开始。
var PENDING = 0; var FULFILLED = 1; VAR REJECTED = 2; function Promise () { // 可以存储这些状态,PENDING、FULFILLED 或 REJECTED var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息 var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数 var handlers = []; function fulfill (result) { state = FULFILLED; value = result; } function reject (error) { state = REJECTED; value = error; } function resolve (result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject); return; } fulfill(result); } catch (e) { reject(e); } } doResolve(fn, resolve, reject); }
你可以看到,我们复用了 doResolve,因为我们有另一个不可信的解析。fn 允许多次调用 resolve 和 reject,甚至抛出异常。我们要确保 promise 只 resolve 一次或 reject 一次,然后再也不会过渡到另一个状态。
4. 观察(使用 .done)
我们现在拥有一个已完成的状态机,但是我们仍没有办法去观察它的变化。我们的最终目的是实现 .then,但是 .done 的语义要简单的多,所以我们首先实现它。
我们这里的目标是实现 promise.done(onFulfilled, onRejected):
- 只调用 onFulfilled 或 onRejected 中的一个
- 它是调用一次
- 它在下一时刻被调用(例如,在 .done 方法已经返回后)
- 不管我们在调用之前或之后是否解决了这个问题,它都被调用了。
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise (fn) { // 可以存储这些状态,PENDING、FULFILLED 或 REJECTED var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息 var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数 var handlers = []; function fulfill(result) { state = FULFILLED; value = result; handlers.forEach(handle); handlers = null; } function reject (result) { state = REJECTED value = result handlers.forEach(handle) handlers = null } function resolve (result) { try { var then = getThen(result) if (then) { doResolve(then, resolve, reject) return } fulfill(result) } catch (ex) { reject(ex) } } function handle (handler) { if (state === PENDING) { handlers.push(handler); } else { if (state === FULFILLED && typeof handlers.onFulfilled === 'function') { handler.onFulfilled(value); } if (state === REJECTED && typeof handlers.onRejected === 'function') { handler.onRejected(value); } } } this.done = function (onFulfilled, onRejected) { // 确保我们总是异步执行的 setTimeout(function () { handler({ onFulfilled: onFulfilled, onRejected: onRejected }) }, 0) } doResolve(fn, resolve, reject); }
当 Promise 被解决或拒绝时,我们要确保去通知 handlers。
5. 观察(使用 .then)
现在我们已经实现了 .done,我们可以简单的实现 .then 来实现相同的事情,但是在程序中构造一个新的 Promise 对象。
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); } }); }); }