返回

Promise改造:在超时内,无论多个实例成功或失败都进入resolved状态

前端

Promise增加超时功能

在原有Promise的基础上增加超时功能,当一个Promise在规定时间内没有被resolved或rejected,则自动触发超时,并以超时为由reject这个Promise。

实现原理

// 1.定义函数 promisifyWithTimeout
const promisifyWithTimeout = (promise, timeoutMs) => {
  // 2.创建新的Promise
  return new Promise((resolve, reject) => {
    // 3.开启定时器,如果超过指定时间,则reject
    const timeoutId = setTimeout(() => {
      reject(new Error('Promise timed out'));
    }, timeoutMs);

    // 4.使用Promise.race来竞争两者谁先完成
    Promise.race([
      promise, // 原有的Promise
      new Promise((resolve, reject) => { // 超时Promise
        setTimeout(() => {
          resolve('Promise timed out'); // 超时后resolve
        }, timeoutMs);
      })
    ])
    .then(
      // 5.如果原有Promise先完成,则resolve
      (result) => {
        clearTimeout(timeoutId); // 清除定时器
        resolve(result); // resolve原有Promise的结果
      },
      // 6.如果超时Promise先完成,则reject
      (reason) => {
        clearTimeout(timeoutId); // 清除定时器
        reject(reason); // reject超时的理由
      }
    );
  });
};

// 7.使用示例
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 2000);
});

promisifyWithTimeout(myPromise, 1000)
  .then((result) => {
    console.log(result); // '成功'
  })
  .catch((reason) => {
    console.log(reason); // 'Promise timed out'
  });

改造Promise.all,确保所有实例都执行完毕

实现原理

将Promise.all重写为:

Promise.allSettled = function (promises) {
  return new Promise((resolve, reject) => {
    let results = [];
    let completed = 0;
    promises.forEach((promise, i) => {
      promise.then(
        (value) => {
          results[i] = { status: 'fulfilled', value };
          if (++completed === promises.length) {
            resolve(results);
          }
        },
        (reason) => {
          results[i] = { status: 'rejected', reason };
          if (++completed === promises.length) {
            resolve(results);
          }
        }
      );
    });
  });
};
// 使用示例
const promise1 = Promise.resolve(3);
const promise2 = Promise.reject(2);
const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 2000);
});

Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
    console.log(results);
    // 结果:[
    //   { status: 'fulfilled', value: 3 },
    //   { status: 'rejected', reason: 2 },
    //   { status: 'fulfilled', value: 1 }
    // ]
  });