实现Promise的all,race,allSettled等

1,442 阅读2分钟

上文我们手写了符合Promises/A+的Promise,文章链接在此。由于promise实现篇幅过长,真正面试的时候,反而是ES6中的部分方法的实现更加容易考到(个人愚见)。 手写各个方法的时候要注意入参和返回值,当然更重要的就是此方法实现了什么样的逻辑。关于ES6中promise的方法,在之前文章有整理。可以参考此篇文章来阅读此文。

Promise.prototype.catch

Promise.prototype.catch相当于是.then(null,rejection)。

class Promise{
	//....
    catch(onRejected){
    	 return this.then(null,onRejected)
    }
}

Promise.prototype.finally

class Promise{
	//....
    finally(onFinally){
      onFinally();
      return this;
    }
}

Promise.resolve

static resolve(value){
    if (value instanceof Promise) {
      return value;
    }
    return new Promise((resolve,reject)=>{
      resolve(value);
    })
}

Promise.reject

static reject(value){
    return new Promise((resolve,reject)=>{
      reject(value);
    })
}

Promise.all

static all(promiseArr){
	//返回新的promise实例
    return new Promise((resolve,reject)=>{
      var length = promiseArr.length
      var result = [];
      for(var i = 0;i<length;i++){
        let _promise = promiseArr[i];
        function handlerResolve(index,item){
          result[index] = item;
          //因为promise完成的时间不尽相同 所以用--length来判断合适全部处理完成
          --length;
          if(length == 0){
            resolve(result);
          }
        }
        Promise.resolve(_promise).then((value)=>{
          handlerResolve(i,value);
        },reason=>{
          //有失败则返回
          reject(reason)
          return;
        })
      }
    })
  }

Promise.race

static race(promiseArr){
    return new Promise((resolve,reject)=>{
      var length = promiseArr.length
      for(var i = 0;i<length;i++){
        let _promise = promiseArr[i];
        //谁先返回结果就返回谁
        Promise.resolve(_promise).then(value=>{
          resolve(value)
          return;
        },reason=>{
          reject(reason)
          return;
        })
      }
    })
 }

Promise.allSettled

static allSettled(promiseArr){
    return new Promise((resolve,reject)=>{
      var length = promiseArr.length
      var result = [];
      for(let i = 0;i<length;i++){
        let _promise = promiseArr[i];
        function handlerResolve(index,item){
          result[index] = item;
          --length;
          if(length == 0){
            resolve(result);
          }
        }
        Promise.resolve(_promise).then((value)=>{
          handlerResolve(i,{status:'fulfilled',value:value});
        },reason=>{
          handlerResolve(i,{status:'rejected',reason:reason});
        })
      }
    })
 }

请用JS实现Ajax并发请求控制

还有一个常问的问题如下:

实现一个批量请求函数 multiRequest(urls, maxNum),要求如下:
• 要求最大并发数 maxNum
• 每当有一个请求返回,就留下一个空位,可以增加新的请求
• 所有请求完成后,结果按照 urls 里面的顺序依次打出

原文链接在此处 下面我做一个代码的搬运工,实现方法如下:

function multiRequest(urls = [], maxNum) {
  // 请求总数量
  const len = urls.length;
  // 根据请求数量创建一个数组来保存请求的结果
  const result = new Array(len).fill(false);
  // 当前完成的数量
  let count = 0;

  return new Promise((resolve, reject) => {
    // 请求maxNum个
    while (count < maxNum) {
      next();
    }
    function next() {
      let current = count++;
      // 处理边界条件
      if (current >= len) {
        // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
        !result.includes(false) && resolve(result);
        return;
      }
      const url = urls[current];
      console.log(`开始 ${current}`, new Date().toLocaleString());
      fetch(url)
        .then((res) => {
          // 保存请求结果
          result[current] = res;
          console.log(`完成 ${current}`, new Date().toLocaleString());
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        })
        .catch((err) => {
          console.log(`结束 ${current}`, new Date().toLocaleString());
          result[current] = err;
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        });
    }
  });
}