Promise 手撕

promise 手撕

手动实现一个完整的 Promise 是一个复杂的任务,包括 Promise 的状态管理、异步任务调度、回调处理等。以下是一个简化版的 Promise 实现,用于演示 Promise 的基本原理:

promise

js 复制代码
class MyPromise {
  constructor(executor) {
    // 初始化 Promise 的状态为 pending
    this.state = 'pending';
    // 初始化 Promise 的结果值为 undefined
    this.value = undefined;
    // 存储 then 方法中的回调函数
    this.handlers = [];

    // 定义 resolve 方法,用于将 Promise 状态从 pending 变为 fulfilled
    const resolve = (value) => {
      // 确保 Promise 的状态只能从 pending 变为 fulfilled
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        // 存储 resolved 的结果值
        this.value = value;
        // 执行所有的回调函数
        this.callHandlers();
      }
    };

    // 定义 reject 方法,用于将 Promise 状态从 pending 变为 rejected
    const reject = (reason) => {
      // 确保 Promise 的状态只能从 pending 变为 rejected
      if (this.state === 'pending') {
        this.state = 'rejected';
        // 存储 rejected 的原因
        this.value = reason;
        // 执行所有的回调函数
        this.callHandlers();
      }
    };

    try {
      // 执行传入的 executor 函数,并将 resolve 和 reject 作为参数传递进去
      executor(resolve, reject);
    } catch (error) {
      // 如果执行过程中出现异常,直接将 Promise 状态置为 rejected
      reject(error);
    }
  }

  // 定义 then 方法,用于添加成功和失败的回调函数
  then(onFulfilled, onRejected) {
    // 返回一个新的 Promise 对象
    return new MyPromise((resolve, reject) => {
      // 定义 fulfilledHandler 函数,用于处理 fulfilled 状态的回调
      const fulfilledHandler = () => {
        if (typeof onFulfilled === 'function') {
          try {
            // 执行 onFulfilled 回调,并将 resolved 的结果传递给它
            const result = onFulfilled(this.value);
            // 将 onFulfilled 回调的结果传递给新的 Promise,从而实现链式调用
            resolve(result);
          } catch (error) {
            // 如果 onFulfilled 回调执行过程中出现异常,将新的 Promise 置为 rejected
            reject(error);
          }
        } else {
          // 如果 onFulfilled 不是函数,直接将 resolved 的结果传递给新的 Promise
          resolve(this.value);
        }
      };

      // 定义 rejectedHandler 函数,用于处理 rejected 状态的回调
      const rejectedHandler = () => {
        if (typeof onRejected === 'function') {
          try {
            // 执行 onRejected 回调,并将 rejected 的原因传递给它
            const result = onRejected(this.value);
            // 将 onRejected 回调的结果传递给新的 Promise,从而实现链式调用
            resolve(result);
          } catch (error) {
            // 如果 onRejected 回调执行过程中出现异常,将新的 Promise 置为 rejected
            reject(error);
          }
        } else {
          // 如果 onRejected 不是函数,直接将 rejected 的原因传递给新的 Promise
          reject(this.value);
        }
      };

      // 如果 Promise 的状态还是 pending,说明回调函数需要等待,将回调函数存储起来
      if (this.state === 'pending') {
        this.handlers.push({ fulfilledHandler, rejectedHandler });
      } else if (this.state === 'fulfilled') {
        // 如果 Promise 已经是 fulfilled 状态,立即执行 fulfilledHandler 回调
        fulfilledHandler();
      } else if (this.state === 'rejected') {
        // 如果 Promise 已经是 rejected 状态,立即执行 rejectedHandler 回调
        rejectedHandler();
      }
    });
  }

  // 定义 catch 方法,用于添加失败的回调函数,实际上就是 then 方法的语法糖
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // 执行所有的回调函数,保证 then 方法注册的回调能被调用
  callHandlers() {
    this.handlers.forEach(({ fulfilledHandler, rejectedHandler }) => {
      if (this.state === 'fulfilled') {
        // 如果 Promise 的状态是 fulfilled,执行 fulfilledHandler 回调
        fulfilledHandler();
      } else if (this.state === 'rejected') {
        // 如果 Promise 的状态是 rejected,执行 rejectedHandler 回调
        rejectedHandler();
      }
    });
  }

  // 定义静态方法 resolve,返回一个 fulfilled 的 Promise 对象
  static resolve(value) {
    return new MyPromise((resolve) => {
      resolve(value);
    });
  }

  // 定义静态方法 reject,返回一个 rejected 的 Promise 对象
  static reject(reason) {
    return new MyPromise((_, reject) => {
      reject(reason);
    });
  }

  // 定义静态方法 all,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
  static all(promises) {
  // 定义静态方法 all,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let resolvedCount = 0;

      promises.forEach((promise, index) => {
        // 将每个 Promise 转换为 MyPromise,确保所有 Promise 都被处理
        MyPromise.resolve(promise).then(
          value => {
            // 存储 resolved 的结果值
            results[index] = value;
            resolvedCount++;

            // 当所有 Promise 都被 resolved 时,将新的 Promise 置为 fulfilled,并传递结果数组
            if (resolvedCount === promises.length) {
              resolve(results);
            }
          },
          // 当有任何一个 Promise 被 rejected 时,将新的 Promise 置为 rejected,并传递原因
          reject
        );
      });
    });
  }

  // 定义静态方法 race,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        // 将每个 Promise 转换为 MyPromise,确保所有 Promise 都被处理
        MyPromise.resolve(promise).then(
          // 当有任何一个 Promise 被 resolved 时,将新的 Promise 置为 fulfilled,并传递结果
          resolve,
          // 当有任何一个 Promise 被 rejected 时,将新的 Promise 置为 rejected,并传递原因
          reject
        );
      });
    });
  }
}

// 测试代码
const promise1 = new MyPromise(resolve => setTimeout(() => resolve(1), 1000));
const promise2 = new MyPromise(resolve => setTimeout(() => resolve(2), 500));
const promise3 = new MyPromise((resolve, reject) => setTimeout(() => reject('error'), 800));

MyPromise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results); // 输出:[1, 2, "error"]
  })
  .catch(error => {
    console.error(error);
  });

MyPromise.race([promise1, promise2, promise3])
  .then(result => {
    console.log(result); // 输出:2
  })
  .catch(error => {
    console.error(error);
  });

Promise.allSettled 是一个 ECMAScript 2020 中引入的新方法,它返回一个在所有给定的 Promise 都已经 fulfilled 或 rejected 后的 Promise,并带有一个对象数组,每个对象表示对应的 Promise 结果。如果一个 Promise 成功了,你会得到一个对象 { status: 'fulfilled', value: resolvedValue },如果一个 Promise 失败了,你会得到一个对象 { status: 'rejected', reason: rejectionReason }

Promise.allSettled

js

js 复制代码
function promiseAllSettled(promises) {
  return new Promise(resolve => {
    const results = [];
    let settledCount = 0;
promises.forEach((promise, index) => {
  Promise.resolve(promise)
    .then(value => {
      results[index] = { status: 'fulfilled', value };
      settledCount++;
      if (settledCount === promises.length) {
        resolve(results);
      }
    })
    .catch(reason => {
      results[index] = { status: 'rejected', reason };
      settledCount++;
      if (settledCount === promises.length) {
        resolve(results);
      }
    });
});
});
}

//输出
const promises = [
  Promise.resolve(1),
  Promise.reject('error'),
  Promise.resolve(3)
];

promiseAllSettled(promises)
  .then(results => {
    console.log(results);
    // 输出:[
    //   { status: 'fulfilled', value: 1 },
    //   { status: 'rejected', reason: 'error' },
    //   { status: 'fulfilled', value: 3 }
    // ]
  });

Promise.any 是 ECMAScript 2021 中引入的新方法,它返回一个在任意给定的 Promise 变为 fulfilled 状态后的 Promise。如果所有 Promise 都处于 rejected 状态,则会返回一个 AggregateError,其中包含所有的 rejection 原因。

Promise.any

js 复制代码
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    let rejectedCount = 0;
    const errors = [];
promises.forEach((promise, index) => {
  Promise.resolve(promise)
    .then(resolve)
    .catch(reason => {
      rejectedCount++;
      errors[index] = reason;
      if (rejectedCount === promises.length) {
        reject(new AggregateError(errors, 'All promises were rejected'));
      }
    });
});
  });
}

//使用上述实现的 promiseAny 函数,你可以按照以下方式调用:

const promises = [
  Promise.reject('Error 1'),
  Promise.resolve(2),
  Promise.reject('Error 3')
];

promiseAny(promises)
  .then(result => {
    console.log(result); // 输出:2
  })
  .catch(error => {
    console.error(error); // 输出:AggregateError: All promises were rejected
  });

Promise.all 是一个非常常用的 Promise 方法,它接收一个 Promise 数组作为输入,返回一个新的 Promise,该 Promise 在所有输入的 Promise 都变为 fulfilled 状态后才会变为 fulfilled 状态,并返回一个包含所有 Promise 结果的数组。如果输入的 Promise 中有一个被 rejected,则返回的 Promise 会立即变为 rejected,并带有第一个被 rejected 的 Promise 的原因。

Promise.all

js 复制代码
function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let fulfilledCount = 0;
promises.forEach((promise, index) => {
  Promise.resolve(promise)
    .then(value => {
      results[index] = value;
      fulfilledCount++;
      if (fulfilledCount === promises.length) {
        resolve(results);
      }
    })
    .catch(reject);
});
  });
}
//使用上述实现的 promiseAll 函数,你可以按照以下方式调用:
const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
];

promiseAll(promises)
  .then(results => {
    console.log(results); // 输出:[1, 2, 3]
  })
  .catch(error => {
    console.error(error);
  });

Promise.race 是一个 Promise 方法,它接收一个 Promise 数组作为输入,返回一个新的 Promise,该 Promise 在输入的 Promise 数组中有任意一个 Promise 变为 fulfilled 或 rejected 状态后,即会变为相应的状态,并带有该 Promise 的结果或原因。

Promise.race

js 复制代码
function promiseRace(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach(promise => {
      Promise.resolve(promise)
        .then(resolve)
        .catch(reject);
    });
  });
}
//使用上述实现的 promiseRace 函数,你可以按照以下方式调用:
const promises = [
  new Promise(resolve => setTimeout(() => resolve(1), 1000)),
  new Promise(resolve => setTimeout(() => resolve(2), 500)),
  new Promise((resolve, reject) => setTimeout(() => reject('error'), 800))
];

promiseRace(promises)
  .then(result => {
    console.log(result); // 输出:2
  })
  .catch(error => {
    console.error(error); // 输出:error
  });

Promise.any 是 ECMAScript 2021 中引入的新方法,它返回一个在任意给定的 Promise 变为 fulfilled 状态后的 Promise。如果所有 Promise 都处于 rejected 状态,则会返回一个 AggregateError,其中包含所有的 rejection 原因。

Promise.any

js 复制代码
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    let rejectedCount = 0;
    const errors = [];

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then(resolve)
        .catch(reason => {
          rejectedCount++;
          errors[index] = reason;
          if (rejectedCount === promises.length) {
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        });
    });
  });
}
//使用上述实现的 promiseAny 函数,你可以按照以下方式调用:
const promises = [
  Promise.reject('Error 1'),
  Promise.resolve(2),
  Promise.reject('Error 3')
];

promiseAny(promises)
  .then(result => {
    console.log(result); // 输出:2
  })
  .catch(error => {
    console.error(error); // 输出:AggregateError: All promises were rejected
  });

并发实现

js 复制代码
function concurrentPromises(promises, concurrency) {
  return new Promise((resolve, reject) => {
    const results = [];
    let runningCount = 0;
    let index = 0;

    // 定义一个递归函数,用于执行下一个 Promise
    function runNext() {
      // 如果已经执行了所有的 Promise,则返回结果
      if (index >= promises.length) {
        resolve(results);
        return;
      }

      // 取出当前要执行的 Promise
      const promise = promises[index];

      // 执行当前 Promise,并更新状态
      runningCount++;
      index++;

      Promise.resolve(promise)
        .then(result => {
          // 当 Promise 执行成功时,将结果存入 results 数组
          results.push(result);
        })
        .catch(error => {
          // 当 Promise 执行失败时,直接返回错误
          reject(error);
        })
        .finally(() => {
          // 当前 Promise 执行完毕,继续执行下一个 Promise
          runningCount--;

          // 如果正在执行的 Promise 数量小于并发数,并且还有未执行的 Promise,则继续执行下一个 Promise
          while (runningCount < concurrency && index < promises.length) {
            runNext();
          }

          // 如果正在执行的 Promise 数量为 0,并且所有 Promise 都执行完毕,则返回结果
          if (runningCount === 0 && index >= promises.length) {
            resolve(results);
          }
        });
    }

    // 启动并发执行
    for (let i = 0; i < concurrency && i < promises.length; i++) {
      runNext();
    }
  });
}

// 测试代码
const delay = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));

const promises = [
  delay(1000, 1),
  delay(2000, 2),
  delay(1500, 3),
  delay(500, 4),
  delay(800, 5),
  delay(1200, 6),
];

concurrentPromises(promises, 3)
  .then(results => {
    console.log(results); // 输出:[1, 2, 3, 4, 5, 6]
  })
  .catch(error => {
    console.error(error);
  });

上述代码中的 concurrentPromises 函数接受一个 Promise 数组 promises 和并发数 concurrency 作为参数。它会并发执行最多 concurrency 个 Promise,然后等待其中一个 Promise 完成后再继续执行下一个 Promise,直到所有 Promise 都执行完毕。

请注意,实际的 Promise 并发实现可能更加复杂,需要考虑更多的错误处理和边界情况。此处提供的是一个简单的示例实现,用于演示并发的基本原理。在实际项目中,建议使用成熟的 Promise 并发库,如 Promise.allPromise.allSettled,来实现并发任务。

总结

Promise的并发性方法常用于处理多个promise的并发执行问题,每个方法应用场景大致总结如下:

  • Promise.all:用于接收多个promise兑现的结果,若其中有reject的会被reject
  • Promise.allSettled:用于接收多个promise兑现/拒绝的结果
  • Promise.any:用于接收多个promise中兑现最快的那个的兑现结果,若全部reject则reject
  • Promise.race:用于接收多个promise中兑现/拒绝最快的那个的处理结果
相关推荐
zpjing~.~3 分钟前
CSS 过渡动画效果
前端·css
Senar7 分钟前
机器学习和前端
前端·人工智能·机器学习
GISer_Jing9 分钟前
React基础知识(总结回顾一)
前端·react.js·前端框架
我叫czc36 分钟前
【Python高级366】静态Web服务器开发
服务器·前端·python
温轻舟42 分钟前
前端开发 -- 自动回复机器人【附完整源码】
前端·javascript·css·机器人·html·交互·温轻舟
赵大仁42 分钟前
深入解析 Vue 3 的核心原理
前端·javascript·vue.js·react.js·ecmascript
csstmg1 小时前
记录一次前端绘画海报的过程及遇到的几个问题
前端
bidepanm1 小时前
Vue.use()和Vue.component()
前端·javascript·vue.js
顾平安1 小时前
手写 PromiseA+ 实现,轻松通过 872 条用例
前端
胡西风_foxww1 小时前
【ES6复习笔记】对象方法扩展(17)
前端·笔记·es6·对象·方法·扩展·对象方法扩展