什么是 Promise
Promise 是一种异步编程的解决方案,它可以更优雅地处理异步函数的执行结果。Promise 可以在异步函数的回调函数中返回一个对象,代表这个异步操作的未来结果。通过 then 方法可以处理这个未来的结果,也可以通过 catch 方法处理这个异步操作的失败情况。Promise 的优点是避免了回调函数陷阱,使得异步编程更加清晰明了。
Promise/A 规范
Promise/A 规范是 Promise 实现的一种标准。该规范定义了一个对象的实现接口,即必须实现 then 方法,可以转换成该规范标准的 Promise 实现都可以进行互操作。Promise 实现必须是一个对象,有一个 then 方法,接收两个参数,分别是成功和失败的回调函数,并返回一个新的 Promise 对象。then 方法可以链式调用;如果当前的 Promise 对象返回一个“pending”状态,说明异步操作正在进行中;如果返回一个“fulfilled”状态,说明异步操作成功,并返回一个结果;如果返回一个“rejected”状态,说明异步操作失败,并返回一个错误。
实现 Promise/A
在 Node.js 中实现 Promise/A,首先需要实现一个 Promise 类。该类有一个构造函数,接收一个 Executor 函数作为参数。Executor 函数有两个参数,resolve 和 reject,分别是异步操作成功和失败的回调函数,它们会在异步操作完成后被调用。
class MyPromise { constructor(executor) { // 初始状态为 pending this.status = 'pending'; this.value = undefined; this.reason = undefined; // 存放成功的回调函数 this.onResolveCallbacks = []; // 存放失败的回调函数 this.onRejectCallbacks = []; const resolve = (value) => { if (this.status === 'pending') { this.status = 'fulfilled'; this.value = value; this.onResolveCallbacks.forEach((callback) => { callback(); }); } } const reject = (reason) => { if (this.status === 'pending') { this.status = 'rejected'; this.reason = reason; this.onRejectCallbacks.forEach((callback) => { callback(); }); } } try { executor(resolve, reject); } catch(e) { reject(e); } } }
接下来,需要实现 then 方法。then 方法接收两个参数,onFulfilled 和 onRejected,分别是异步操作成功和失败的回调函数。如果异步操作成功,会依次执行 onFulfilled;如果异步操作失败,会依次执行 onRejected。如果 onFulfilled 和 onRejected 都不是函数,就直接返回当前的 Promise 对象。如果异步操作还没有完成,仍然处于“pending”状态,就把 onFulfilled 和 onRejected 存放到回调函数的队列中;如果异步操作已经完成,就立即执行对应的回调函数。
MyPromise.prototype.then = function(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = (value) => value; } if (typeof onRejected !== 'function') { onRejected = (reason) => { throw reason; } } const promise2 = new MyPromise((resolve, reject) => { const resolvePromise = (promise2, x, resolve, reject) => { if (promise2 === x) { return reject(new TypeError('循环引用')); } let called = false; if ((typeof x === 'object' && x !== null) || typeof x === 'function') { try { const then = x.then; if (typeof then === 'function') { then.call(x, (y) => { if (called) { return ; } called = true; resolvePromise(promise2, y, resolve, reject); }, (r) => { if (called) { return ; } called = true; reject(r); }); } else { resolve(x); } } catch(e) { if (called) { return ; } called = true; reject(e); } } else { resolve(x); } } if (this.status === 'fulfilled') { setTimeout(() => { try { const x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch(e) { reject(e); } }, 0); } if (this.status === 'rejected') { setTimeout(() => { try { const x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch(e) { reject(e); } }, 0); } if (this.status === 'pending') { this.onResolveCallbacks.push(() => { setTimeout(() => { try { const x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch(e) { reject(e); } }, 0); }); this.onRejectCallbacks.push(() => { setTimeout(() => { try { const x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch(e) { reject(e); } }, 0); }); } }); return promise2; }
在实现 then 方法的过程中,需要注意处理 then 方法的链式调用。当调用 then 方法时,需要返回一个新的 Promise 对象,可以让多个 then 方法链式调用。
最后,实现 catch 方法。catch 方法用来捕捉 Promise 中的异常情况,并返回一个新的 Promise 对象。
MyPromise.prototype.catch = function(onRejected) { return this.then(null, onRejected); }
使用示例
const promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('Hello World'); }, 1000); }).then((value) => { console.log(value); return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('Promise chain'); }, 1000); }); }).then((value) => { console.log(value); }).catch((reason) => { console.log(reason); });
总结
Promise/A 规范是异步编程的标准之一,使用标准化的 API 可以提高代码的重用性和可维护性。Node.js 开始尝试实现 Promise/A,深入理解其实现原理可以更加灵活地应用到开发中去,提高代码的可读性和可维护性。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a1b31fadd4f0e0ff9ba1f4