三十的博客

实现 Promise

本文内容基于 AI 生成结果整理,可能包含不准确信息,仅供参考使用。
发布时间
阅读量 加载中...

跟着 AI 学习手搓一个 Promise 类

v1.0 最基础版本

状态管理 + 同步 then

js
class MyPromise {
  constructor(executor) {
    this.state = "pending"; // 三种状态: pending, fulfilled, rejected
    this.value = undefined; // 成功的结果
    this.reason = undefined; // 失败的原因

    const resolve = (value) => {
      if (this.state == "pending") {
        this.state = "fulfilled";
        this.value = value;
      }
    };

    const reject = (reason) => {
      if (this.state == "pending") {
        this.state = "rejected";
        this.reason = reason;
      }
    };

    // 立即执行
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // 基础 then 方法,只处理同步
  then(onFulfilled, onRejected) {
    if (this.state == "fulfilled") {
      onFulfilled(this.value);
    }
    if (this.state == "rejected") {
      onRejected(this.reason);
    }
  }
}

// 测试 v1.0
console.log("v1.0 测试");

const p1 = new MyPromise((resolve) => {
  resolve("success!");
});

p1.then((value) => console.log(value));

v2.0 支持异步操作

js
class MyPromise {
  constructor(executor) {
    this.state = "pending";
    this.value = undefined;
    this.reason = undefined;

    // 新增:回调队列
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state == "pending") {
        this.state = "fulfilled";
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state == "pending") {
        this.state = "rejected";
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    if (this.state == "fulfilled") {
      onFulfilled(this.value);
    }
    if (this.state == "rejected") {
      onRejected(this.reason);
    }
    if (this.state == "pending") {
      // 将回调存入队列
      this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
      this.onRejectedCallbacks.push(() => onRejected(this.reason));
    }
  }
}

// 测试 v2.0
console.log("v2.0 测试");

const p2 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve("sync success!");
  }, 1000);
});

p2.then((value) => console.log(value));

v3.0 实现链式调用

js
class MyPromise {
  constructor(executor) {
    this.state = "pending";
    this.value = undefined;
    this.reason = undefined;

    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state == "pending") {
        this.state = "fulfilled";
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state == "pending") {
        this.state = "rejected";
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 处理值穿透:如果不是函数,就创建默认函数
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    // 返回新的 Promise
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === "fulfilled") {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === "rejected") {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === "pending") {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolve(x);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
    return promise2;
  }
}

// 测试 v3.0
console.log("v3.0 测试");

const p3 = new MyPromise((resolve) => {
  resolve(1);
});

p3.then((value) => {
  console.log("第一次:", value); // 1
  return value + 1;
})
  .then((value) => {
    console.log("第二次:", value); // 2
    return new MyPromise((resolve) => resolve(value + 1));
  })
  .then((value) => {
    console.log("第三次:", value); // 3
  });

setTimeout 0 的关键作用

v4.0 处理 Promise 返回值

js
class MyPromise {
  constructor(executor) {
    this.state = "pending";
    this.value = undefined;
    this.reason = undefined;

    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state == "pending") {
        this.state = "fulfilled";
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state == "pending") {
        this.state = "rejected";
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    const promise2 = new MyPromise((resolve, reject) => {
      const handleCallback = (callback, valueOrReason) => {
        setTimeout(() => {
          try {
            const x = callback(valueOrReason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };

      if (this.state === "fulfilled") {
        handleCallback(onFulfilled, this.value);
      } else if (this.state === "rejected") {
        handleCallback(onRejected, this.reason);
      } else if (this.state === "pending") {
        this.onFulfilledCallbacks.push(() =>
          handleCallback(onFulfilled, this.value)
        );
        this.onRejectedCallbacks.push(() =>
          handleCallback(onRejected, this.reason)
        );
      }
    });

    return promise2;
  }

  // 添加 catch 方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }
}

// Promise 解析函数
function resolvePromise(promise2, x, resolve, reject) {
  // 防止循环引用
  if (promise2 === x) {
    return reject(new TypeError("循环引用"));
  }

  // 如果 x 是 promise
  if (x instanceof MyPromise) {
    x.then((y) => resolvePromise(promise2, y, resolve, reject), reject);
  }
  // 如果 x 是对象或函数
  else if (x !== null && (typeof x === "object" || typeof x === "function")) {
    let then;
    try {
      then = x.then;
    } catch (error) {
      return reject(error);
    }

    if (typeof then === "function") {
      let called = false;
      try {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } catch (error) {
        if (!called) {
          reject(error);
        }
      }
    } else {
      resolve(x);
    }
  }
  // 基本类型直接 resolve
  else {
    resolve(x);
  }
}

// 测试 v4.0
console.log("v4.0 测试");
const p4 = new MyPromise((resolve) => resolve(1));
p4.then((value) => {
  console.log("值:", value);
  return new MyPromise((resolve) => resolve(value + 1));
})
  .then((value) => {
    console.log("新 Promise 返回值:", value);
    return { data: value + 1 };
  })
  .then((value) => {
    console.log("对象返回值:", value);
  });

v5.0 添加静态方法

js
class MyPromise {
  constructor(executor) {
    this.state = "pending";
    this.value = undefined;
    this.reason = undefined;

    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state == "pending") {
        this.state = "fulfilled";
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state == "pending") {
        this.state = "rejected";
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    const promise2 = new MyPromise((resolve, reject) => {
      const handleCallback = (callback, valueOrReason) => {
        setTimeout(() => {
          try {
            const x = callback(valueOrReason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };

      if (this.state === "fulfilled") {
        handleCallback(onFulfilled, this.value);
      } else if (this.state === "rejected") {
        handleCallback(onRejected, this.reason);
      } else if (this.state === "pending") {
        this.onFulfilledCallbacks.push(() =>
          handleCallback(onFulfilled, this.value)
        );
        this.onRejectedCallbacks.push(() =>
          handleCallback(onRejected, this.reason)
        );
      }
    });

    return promise2;
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  static resolve(value) {
    if (value instanceof MyPromise) {
      return value;
    }

    if (value && typeof value.then === "function") {
      return new MyPromise(value.then);
    }

    return new MyPromise((resolve) => resolve(value));
  }

  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason));
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let completed = 0;

      if (promises.length === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then((value) => {
          results[index] = value;
          completed++;
          if (completed === promises.length) {
            resolve(results);
          }
        }, reject);
      });
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

  static allSettled(promises) {
    return new MyPromise((resolve) => {
      const results = [];
      let completed = 0;

      const processResult = (index, status, valueOrReason) => {
        results[index] =
          status === "fulfilled"
            ? { status: "fulfilled", value: valueOrReason }
            : { status: "rejected", reason: valueOrReason };
        completed++;
        if (completed === promises.length) {
          resolve(results);
        }
      };

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => processResult(index, "fulfilled", value),
          (reason) => processResult(index, "rejected", reason)
        );
      });
    });
  }

  finally(callback) {
    return this.then(
      (value) => MyPromise.resolve(callback()).then(() => value),
      (reason) =>
        MyPromise.resolve(callback()).then(() => {
          throw reason;
        })
    );
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("循环引用"));
  }

  if (x instanceof MyPromise) {
    x.then((y) => resolvePromise(promise2, y, resolve, reject), reject);
  } else if (x !== null && (typeof x === "object" || typeof x === "function")) {
    let then;
    try {
      then = x.then;
    } catch (error) {
      return reject(error);
    }

    if (typeof then === "function") {
      let called = false;
      try {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } catch (error) {
        if (!called) {
          reject(error);
        }
      }
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
}

// 测试 v5.0
console.log("v5.0 测试");

// 测试 MyPromise.all
MyPromise.all([
  MyPromise.resolve(1),
  MyPromise.resolve(2),
  new MyPromise((resolve) => setTimeout(() => resolve(3), 100)),
]).then((values) => {
  console.log("all 结果:", values); // [1, 2, 3]
});

// 测试 MyPromise.race
MyPromise.race([
  new MyPromise((resolve) => setTimeout(() => resolve("快的"), 50)),
  new MyPromise((resolve) => setTimeout(() => resolve("慢的"), 100)),
]).then((value) => {
  console.log("race 结果:", value); // "快的"
});

// 测试 MyPromise.resolve/reject
MyPromise.resolve("直接成功").then(console.log);
MyPromise.reject("直接失败").catch(console.error);

最终完整版本

js
class MyPromise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.state = MyPromise.PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state !== MyPromise.PENDING) return;

      // 处理 thenable 对象
      if (value && typeof value.then === "function") {
        value.then(resolve, reject);
        return;
      }

      this.state = MyPromise.FULFILLED;
      this.value = value;
      this.onFulfilledCallbacks.forEach((fn) => fn());
    };

    const reject = (reason) => {
      if (this.state !== MyPromise.PENDING) return;

      this.state = MyPromise.REJECTED;
      this.reason = reason;
      this.onRejectedCallbacks.forEach((fn) => fn());
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (e) => {
            throw e;
          };

    const promise2 = new MyPromise((resolve, reject) => {
      const handleFulfilled = () => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };

      const handleRejected = () => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      };

      if (this.state === MyPromise.FULFILLED) {
        handleFulfilled();
      } else if (this.state === MyPromise.REJECTED) {
        handleRejected();
      } else {
        this.onFulfilledCallbacks.push(handleFulfilled);
        this.onRejectedCallbacks.push(handleRejected);
      }
    });

    return promise2;
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(callback) {
    return this.then(
      (value) => MyPromise.resolve(callback()).then(() => value),
      (reason) =>
        MyPromise.resolve(callback()).then(() => {
          throw reason;
        })
    );
  }

  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((resolve) => resolve(value));
  }

  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason));
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let count = 0;

      const processResult = (index, value) => {
        results[index] = value;
        if (++count === promises.length) {
          resolve(results);
        }
      };

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => processResult(index, value),
          reject
        );
      });
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

  static allSettled(promises) {
    return new MyPromise((resolve) => {
      const results = [];
      let count = 0;

      const processResult = (index, status, valueOrReason) => {
        results[index] =
          status === "fulfilled"
            ? { status: "fulfilled", value: valueOrReason }
            : { status: "rejected", reason: valueOrReason };
        if (++count === promises.length) {
          resolve(results);
        }
      };

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => processResult(index, "fulfilled", value),
          (reason) => processResult(index, "rejected", reason)
        );
      });
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("循环引用"));
  }

  if (x instanceof MyPromise) {
    x.then((y) => resolvePromise(promise2, y, resolve, reject), reject);
  } else if (x && (typeof x === "object" || typeof x === "function")) {
    let then;
    try {
      then = x.then;
    } catch (error) {
      return reject(error);
    }

    if (typeof then === "function") {
      let called = false;
      try {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } catch (error) {
        if (!called) reject(error);
      }
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
}
#Promise