手写 Promise
- 了解Promise
- 定义一个 Promise
- 定义 then 方法
- 判断 Promise 的状态
- 定义 static 方法 resolve 和 reject
了解Promise
Promise 是一种异步编程解决方案,它提供了一种更加优美和便捷的方式来处理异步操作。下面是手写 Promise 的详细步骤和分析。
首先,我们需要了解 Promise 的三种状态:
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
当一个 Promise 被创建时,它的状态是 Pending。当 Promise 成功执行回调函数时,它的状态变成 Fulfilled。如果执行回调函数时发生了异常,Promise 的状态会变成 Rejected。
定义一个 Promise
接下来,我们需要定义一个 Promise 构造函数,它需要一个执行器函数作为参数。执行器函数接受两个参数 resolve 和 reject,它们是两个函数,用于修改 Promise 的状态。
class MyPromise {constructor(executor) {this.status = 'pending';this.value = undefined;this.reason = undefined;this.onResolvedCallbacks = [];this.onRejectedCallbacks = [];const resolve = (value) => {if (this.status === 'pending') {this.status = 'fulfilled';this.value = value;this.onResolvedCallbacks.forEach((fn) => fn());}};const reject = (reason) => {if (this.status === 'pending') {this.status = 'rejected';this.reason = reason;this.onRejectedCallbacks.forEach((fn) => fn());}};try {executor(resolve, reject);} catch (e) {reject(e);}}
}
在构造函数中,我们定义了 Promise 的状态和值。onResolvedCallbacks 和 onRejectedCallbacks 数组用于存储 then 方法中传入的回调函数,当 Promise 的状态改变时,我们需要依次执行这些回调函数。
定义 then 方法
然后,我们需要定义 then 方法,它接受两个参数 onFulfilled 和 onRejected,它们分别是 Promise 成功和失败时的回调函数。
class MyPromise {// ...then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;onRejected =typeof onRejected === 'function'? onRejected: (reason) => {throw reason;};const promise2 = new MyPromise((resolve, reject) => {if (this.status === 'fulfilled') {setTimeout(() => {try {const x = onFulfilled(this.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}}, 0);} else if (this.status === 'rejected') {setTimeout(() => {try {const x = onRejected(this.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}}, 0);} else if (this.status === 'pending') {this.onResolvedCallbacks.push(() => {setTimeout(() => {try {const x = onFulfilled(this.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}}, 0);});this.onRejectedCallbacks.push(() => {setTimeout(() => {try {const x = onRejected(this.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}}, 0);});}});return promise2;}
}
判断 Promise 的状态
在 then 方法中,我们首先需要判断 Promise 的状态。如果状态为 Fulfilled,直接调用 onFulfilled 回调函数,并且将返回值传入 resolvePromise 函数。resolvePromise 函数用于处理返回值,如果返回值为 Promise,则等待其状态改变后再传递结果。
如果状态为 Rejected,直接调用 onRejected 回调函数,并且将返回值传入 resolvePromise 函数。
如果状态为 Pending,将回调函数 push 到回调队列中。当 Promise 的状态改变时,依次执行这些回调函数,并在执行完成后,再调用 resolvePromise 函数。
在 resolvePromise 函数中,我们需要判断返回值的类型。如果为 Promise,则等待其状态改变后再传递结果。
function resolvePromise(promise2, x, resolve, reject) {if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise'));}let called = false;if (x != null && (typeof x === 'object' || 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);}
}
在 resolvePromise 函数中,我们首先需要判断 x 和 promise2 是否相等,如果相等,说明出现了循环引用,需要抛出错误。
然后,我们需要判断 x 的类型。如果 x 是对象或函数,我们需要判断它是否有 then 方法。如果有 then 方法,则说明 x 是 Promise,需要等待其状态改变后再传递结果。否则,直接将 x 传递给 resolve 函数。
定义 static 方法 resolve 和 reject
最后,我们需要在 Promise 类中定义 static 方法 resolve 和 reject,用于创建已经成功和失败的 Promise。
class MyPromise {// ...static resolve(value) {if (value instanceof MyPromise) {return value;}return new MyPromise((resolve) => resolve(value));}static reject(reason) {return new MyPromise((resolve, reject) => reject(reason));}
}
最终,我们得到了手写的 Promise 实现。