[JS]带你手写Promise.all/race

718 阅读2分钟

最近想重新系统地整理一下前端的知识,因此写了这个专栏。我会尽量写一些业务相关的小技巧和前端知识中的重点内容,核心思想。

前言

在之前我们讲过手写promise的实现(点击回顾),但忽略了Promise类上的方法。今天我们就来补全一下。

Promise.all

Promise.all接受一个参数,参数是一个iterable类型。并返回一个新的promise对象。新promise对象的状态会根据iterable中的每一个promise的状态:

  • 如果某一个promise的状态reject了。新的promise状态就会转成reject,result是第一个reject的promise的result。
  • 如果所有的promise都resolve了,新promise的状态就是fulfilled,result是一个数组,每项对应入参的promise的执行结果。

示例

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

手写

class Promise{
	//...
  all(promiseList){
    // 判断入参是否为iterable类型
    if (typeof promiseList.forEach === "undefined") {                        
    	return new Error('param is not iterable')
  	}
  	return new Promise((resolve, reject) => {
    	for (let i = 0; i < promiseList.length; i++) {
      	const res = []
      	let counter = 0                       
      	for (let i = 0; i < promiseList.length; i++) {
          // 直接利用Promise.resolve处理结果,就不用自己判断类型。
        	Promise.resolve(promiseList[i]).then(res => {
          	counter++                  
          	res[i] = res
            //	 当所有都成功了之后执行resolve
          	if (counter === promiseList.length) {
	            resolve(res)
  	        }
            // 只要有一个抛错了,就执行reject。
    	    	}).catch(e => reject(e))
      		}
    		}
  		})
		}
  }
}

Promise.race

Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

示例

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// expected output: "two"

手写

class Promise{
	... 
  race(promiseList){
     // 判断入参是否为iterable类型
    if (typeof promiseList.forEach === "undefined") {                        
    	return new Error('param is not iterable')
  	}
    let used = false;
    return new Promise((resolve, reject) => {
    	for (let i = 0; i < promiseList.length; i++) {
      	const res = [];                    
      	for (let i = 0; i < promiseList.length; i++) {
          // 直接利用Promise.resolve处理结果,就不用自己判断类型。
        	Promise.resolve(promiseList[i]).then(res => {
            // 只要有一个成功了,就执行resolve。
            if(!used){
              used = true;
              resolve(res);
            }
            // 只要有一个抛错了,就执行reject。
    	    	}).catch(e => {
          		if(!used){
                            used = true;
                            reject(e);
                        }
          	})
            }
    	}
      })
  }
}

总结

比起Promise的手写,all和race方法就相对简单多了。思路就是判断用counter记录处理的promise的次数,以及用标识记录某函数执行过没有。希望对大家有所帮助。

参考

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…