logo

可能是目前最易理解的手写Promise:从零实现异步核心

作者:狼烟四起2025.09.19 12:47浏览量:0

简介:本文通过分步骤拆解Promise核心机制,结合代码示例与可视化流程图,系统讲解如何从零实现一个符合A+规范的Promise。内容覆盖状态管理、链式调用、异常处理等关键模块,并附完整实现代码与测试用例。

一、Promise核心机制解析

Promise作为现代JavaScript异步编程的基石,其设计本质是解决”回调地狱”与”信任问题”。标准Promise对象包含三个关键要素:

  1. 状态机:pending → fulfilled/rejected的单向转换
  2. 微任务队列:通过queueMicrotask实现的异步调度
  3. 链式调用:基于.then()方法的值透传与错误冒泡

1.1 状态管理实现

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending'; // 初始状态
  4. this.value = undefined; // 成功值
  5. this.reason = undefined; // 失败原因
  6. this.callbacks = []; // 存储then回调
  7. const resolve = (value) => {
  8. if (this.state === 'pending') {
  9. this.state = 'fulfilled';
  10. this.value = value;
  11. // 执行所有成功回调
  12. this.callbacks.forEach(cb => cb.onResolve(value));
  13. }
  14. };
  15. const reject = (reason) => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected';
  18. this.reason = reason;
  19. // 执行所有失败回调
  20. this.callbacks.forEach(cb => cb.onReject(reason));
  21. }
  22. };
  23. try {
  24. executor(resolve, reject);
  25. } catch (err) {
  26. reject(err);
  27. }
  28. }
  29. }

状态转换遵循严格规则:一旦状态从pending改变,将不可逆。这种设计保证了异步操作的确定性。

1.2 异步调度原理

标准Promise使用微任务(Microtask)而非宏任务(Macrotask)实现异步,确保在当前事件循环结束前执行:

  1. // 简化版微任务调度
  2. const scheduleMicrotask = (callback) => {
  3. queueMicrotask(callback); // 现代浏览器原生支持
  4. // 或使用MutationObserver兼容旧环境
  5. };

这种设计使Promise的.then()回调优先级高于setTimeout等宏任务,形成明确的执行顺序。

二、链式调用实现

链式调用的核心在于.then()方法返回新Promise的特性,结合值透传与错误冒泡机制:

2.1 基本链式结构

  1. MyPromise.prototype.then = function(onResolve, onReject) {
  2. // 参数可选处理
  3. onResolve = typeof onResolve === 'function' ? onResolve : v => v;
  4. onReject = typeof onReject === 'function' ? onReject : r => { throw r; };
  5. const promise2 = new MyPromise((resolve, reject) => {
  6. const handleFulfilled = (value) => {
  7. try {
  8. const x = onResolve(value);
  9. resolvePromise(promise2, x, resolve, reject);
  10. } catch (e) {
  11. reject(e);
  12. }
  13. };
  14. const handleRejected = (reason) => {
  15. try {
  16. const x = onReject(reason);
  17. resolvePromise(promise2, x, resolve, reject);
  18. } catch (e) {
  19. reject(e);
  20. }
  21. };
  22. if (this.state === 'fulfilled') {
  23. scheduleMicrotask(() => handleFulfilled(this.value));
  24. } else if (this.state === 'rejected') {
  25. scheduleMicrotask(() => handleRejected(this.reason));
  26. } else {
  27. this.callbacks.push({
  28. onResolve: handleFulfilled,
  29. onReject: handleRejected
  30. });
  31. }
  32. });
  33. return promise2;
  34. };

2.2 异步值解析协议

resolvePromise函数处理thenable对象的解析,遵循A+规范:

  1. function resolvePromise(promise2, x, resolve, reject) {
  2. // 防止循环引用
  3. if (promise2 === x) {
  4. return reject(new TypeError('Chaining cycle detected'));
  5. }
  6. let called = false;
  7. if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
  8. try {
  9. const then = x.then;
  10. if (typeof then === 'function') {
  11. then.call(
  12. x,
  13. y => {
  14. if (called) return;
  15. called = true;
  16. resolvePromise(promise2, y, resolve, reject);
  17. },
  18. r => {
  19. if (called) return;
  20. called = true;
  21. reject(r);
  22. }
  23. );
  24. } else {
  25. resolve(x);
  26. }
  27. } catch (e) {
  28. if (called) return;
  29. called = true;
  30. reject(e);
  31. }
  32. } else {
  33. resolve(x);
  34. }
  35. }

该实现确保当thenable对象(如另一个Promise)被返回时,能正确解析其最终状态。

三、静态方法实现

标准Promise包含的静态方法可通过类似机制实现:

3.1 Promise.resolve/reject

  1. MyPromise.resolve = function(value) {
  2. if (value instanceof MyPromise) {
  3. return value;
  4. }
  5. return new MyPromise(resolve => resolve(value));
  6. };
  7. MyPromise.reject = function(reason) {
  8. return new MyPromise((_, reject) => reject(reason));
  9. };

3.2 Promise.all实现

  1. MyPromise.all = function(promises) {
  2. return new MyPromise((resolve, reject) => {
  3. const results = [];
  4. let completed = 0;
  5. if (promises.length === 0) {
  6. resolve(results);
  7. }
  8. promises.forEach((promise, index) => {
  9. MyPromise.resolve(promise).then(
  10. value => {
  11. results[index] = value;
  12. completed++;
  13. if (completed === promises.length) {
  14. resolve(results);
  15. }
  16. },
  17. reason => reject(reason)
  18. );
  19. });
  20. });
  21. };

四、实际应用建议

  1. 调试技巧:在.then()中始终返回明确值,避免隐式返回值
    ```javascript
    // 不推荐
    promise.then(value => {
    doSomething(value); // 无返回值,下一个then将收到undefined
    });

// 推荐
promise.then(value => {
doSomething(value);
return processedValue;
});

  1. 2. **错误处理**:使用catch()进行集中错误处理
  2. ```javascript
  3. // 优于多个.then(null, errHandler)
  4. getData()
  5. .then(process)
  6. .then(transform)
  7. .catch(handleError);
  1. 性能优化:避免在循环中创建大量Promise,考虑批量处理
    ```javascript
    // 低效实现
    const promises = [];
    for (let i = 0; i < 1000; i++) {
    promises.push(fetchData(i)); // 同步创建1000个Promise
    }

// 优化方案
async function batchFetch(start, end) {
const results = [];
for (let i = start; i < end; i++) {
results.push(await fetchData(i)); // 顺序执行,控制并发
}
return results;
}

  1. # 五、完整实现代码
  2. ```javascript
  3. // 完整实现见上文各模块组合
  4. // 测试用例
  5. const test = new MyPromise(resolve => {
  6. setTimeout(() => resolve(1), 1000);
  7. });
  8. test
  9. .then(v => {
  10. console.log(v); // 1
  11. return v * 2;
  12. })
  13. .then(v => {
  14. console.log(v); // 2
  15. throw new Error('error');
  16. })
  17. .catch(e => {
  18. console.error(e.message); // 'error'
  19. return 3;
  20. })
  21. .then(v => {
  22. console.log(v); // 3
  23. });

通过这种模块化实现方式,开发者可以清晰理解Promise每个环节的工作原理。建议在实际项目中,先基于这种简化版实现理解核心机制,再逐步使用原生Promise或成熟的库(如bluebird)以获得更好的性能和兼容性。

相关文章推荐

发表评论