【手写 Promise 源码】第十二篇 - Promise.race 的实现

734 阅读2分钟

一,前言

上一篇,主要实现 Promise 的核心静态 API(类方法):Promise.all,主要涉及以下几个点:

  • 测试原生 Promise.all 的使用;
  • Promise.all 的功能与特性分析;
  • Promise.all 的源码实现、执行分析、功能测试;

本篇,继续实现 Promise 静态 API(类方法):Promise.race;

备注:

  • Promise.race 与 Promise.all 实现原理相似;有了 all 的基础 race 就非常简单了;
  • Promise.race 面试高频考察点,主要用于解决超时中断问题;

二,Promise.race 简介

1,API 介绍

race:译为“比赛”、“赛跑”;MDN 参考资料

image.png

Promise.race功能(与 Promise.all 对比):

Promise.all

  • 批处理 promise,返回 promise;
  • 全部成功才成功,返回全部结果;
  • 一个出错就失败,返回第一个失败结果;

Promise.race

  • 批处理 promise,返回 promise;
  • 无论成功还是失败,谁快就返回谁;

2,原生 Promise.race 功能测试

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("Promise 执行完成:成功")
    resolve('success')
  }, 1000);
})

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("Promise 执行完成:失败")
    reject('fail')
  }, 3000);
})

Promise.race([p1, p2]).then((data) => {
  console.log('then', data);
}).catch((err) => {
  console.log('catch', err);
})

// 执行结果:
// 1 秒后打印“Promise 执行完成:成功” + “then success”;
// 3 秒后打印“Promise 执行完成:失败”;

备注:

  • 虽然Promise.race在 1 秒后就返回了结果,但实际一共执行了 3 秒才完成;
  • 如果数组传入数字,会直接返回成功;

三,Promise.race 实现

1,原理分析

  • Promise.race:入参是一个 promise 集合;返回一个 Promise 实例; Promise.race 内部 return new Promise(...)
  • 执行所有 promise,使用最先返回的结果(不管成功还是失败); p.then(resolve, reject) 就看谁先进入 then;

2,代码实现

  static race (promises) {
    return new Promise((resolve, reject)=>{
      for(let i = 0; i < promises.length; i++){
        let p = promises[i];
        if(p && typeof p.then === 'function'){
          p.then(resolve, reject) // 使用第一个执行成功的结果
        }else{
          resolve(p)
        }
      }
    })
  }

3,功能测试

传入数字、成功/失败 promise,表现与原生 promise 一致


四,Promise.race 应用:解决超时问题

借助 Promise.race 特性,为 promise 绑个炸弹:

// 包装 promise,使之具备新功能:控制 promise 状态
function wrap(p1){
  let abort;
  let p = new Promise((resolve, reject)=>{
    // 拿到 p 的 reject,以便于随时更新 p 的状态
    abort = reject; 
  })
  
  // Promise.race:相当于给 p1 绑了一个定时炸弹 p
  let p2 = Promise.race([p, p1]);
  p2.abort = abort;// p2 就获得炸弹的遥控器 
                    
  return p2;
}

超时了,就直接引爆:

let p1 = new Promise((resolve, reject)=>{
  abort = reject;
  setTimeout(() => {
    resolve('成功')
  }, 3000);
})

let p2 = wrap(p1);

p2.then((data)=>{
  console.log('then', data)
},(err)=>{
  console.log('err', err)
})
setTimeout(() => {
   p2.abort('已超时')
}, 1000);

// 执行结果:1 秒后输出"err 已超时",3 秒全部执行完成

五,结尾

本篇,主要实现了 Promise 静态 API(类方法):Promise.race,主要涉及以下几个点:

  • 测试原生 Promise.race 的使用;
  • Promise.race 的功能与特性分析;
  • Promise.race 的源码实现、执行分析、功能测试;

下一篇,继续 Promise 静态 API:Promise.allSettledPromise.any


维护记录

  • 20211106
    • 添加 Promise.race 应用;(仍需完善)