最近面试老是被问到这个,所以记录一下
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
demo:
let p1 = new Promise((resolve, reject) => { resolve('成功了') }) let p2 = new Promise((resolve, reject) => { resolve('success') }) let p3 = Promse.reject('失败') Promise.all([p1, p2]).then((result) => { console.log(result) //['成功了', 'success'] }).catch((error) => { console.log(error) }) Promise.all([p1,p3,p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 失败了,打出 '失败' })
如何自己实现一个promise.all呢
1、如果传参对象为空
function myPromiseAll(arr) { // 定义一个数组 let result = []; return new Promise((resolve, reject) => { // 现在只考虑 “在完成情况下” ,会返回一个数组 resolve(result); }); } let pResult = myPromiseAll([]); pResult.then(value=>{ console.log(pResult); // 输出 Promise { <state>: "fulfilled", <value>: [] } console.log(value); // 输出:[] })
2、如果传参对象不是promise
function myPromiseAll(arr) { let result = []; return new Promise((resolve, reject) => { for(let i = 0; i < arr.length; i++) { result.push(arr[i]); } resolve(result); }); } let pResult = myPromiseAll([1,2,3]); // 元素不是Promise实例 pResult.then(value=>{ console.log(pResult); // 输出: Promise { <state>: "fulfilled", <value>: (3) […] } console.log(value); // 输出: Array(3) [ 1, 2, 3 ] })
3、综合所有情况
function myPromiseAll(arr) { let result = []; return new Promise((resolve, reject) => { // 数组为空,直接resolve了 if(arr.length == 0) { resolve(result); } for(let i = 0; i < arr.length; i++) { if(arr[i].then) { // 若元素是Promise实例,则会有then函数,这里只是简单的作为判断标准 // 元素是Promise arr[i].then(value => { console.log(value); result[i] = value; // 想一想什么时候resolve呢?--- 所有Promise实例都完成了 if(result.length == arr.length) { console.log("所有都完成了") resolve(result); } }) } else { result.push(arr[i]); // 这段代码跟上面重复,想想,能不能提取放到外面,会出现什么情况呢? if(result.length == arr.length) { resolve(result); } } } }); } let p1 = new Promise((resolve, reject)=> { setTimeout(resolve, 2000, "P1 resolved"); }) let p2 = new Promise((resolve, reject)=> { setTimeout(resolve, 3000, "P2 resolved"); }) let p3 = new Promise((resolve, reject)=> { setTimeout(resolve, 4000, "P3 resolved"); }) let pResult = myPromiseAll([p1,p2,p3]); pResult.then(value=>{ console.log(pResult); console.log(value); }) // 输出 // P1 resolved // P2 resolved // P3 resolved // 所有都完成了 // Promise { <state>: "fulfilled", <value>: (3) […] } // Array(3) [ "P1 resolved", "P2 resolved", "P3 resolved" ]
4、如何传入的promise中有失败的呢?
function myPromiseAll(arr) { let result = []; return new Promise((resolve, reject) => { // 如果数组为空,直接返回空数组 if(arr.length == 0) { resolve(result); } for(let i = 0; i < arr.length; i++) { if(arr[i].then) { // 若元素是Promise实例,则会有then函数,这里只是简单的作为判断标准 // 元素是Promise arr[i].then(value => { console.log(value); result.push(value); // 想一想什么时候resolve呢? if(result.length == arr.length) { console.log("所有都成功了") resolve(result); } }, err => { console.log("很不幸,其中一个失败了"); // 注意到没, 这里没有像上面的判断 result.length == arr.length, 为什么? // 只要碰到 resolve 或 reject ,就结束了 reject(err); }) } else { result.push(arr[i]); // 这段代码跟上面重复,想想,能不能提取放到外面,会出现什么情况呢? if(result.length == arr.length) { resolve(result); } } } }); } let p1 = new Promise((resolve, reject)=> { setTimeout(reject, 2000, "P1 rejected"); }) let p2 = new Promise((resolve, reject)=> { setTimeout(resolve, 3000, "P2 resolved"); }) let p3 = new Promise((resolve, reject)=> { setTimeout(resolve, 4000, "P3 resolved"); }) let pResult = myPromiseAll([p1,p2,p3]); pResult.then(value=>{ console.log(pResult); // 是输出成功 console.log(value); }, err => { console.log(pResult); // 还是输出失败呢? console.log(err); }) // 输出 // 很不幸,其中一个失败了 // Promise { <state>: "rejected" } // P1 rejected // P2 resolved // P3 resolved
知乎上看到的一个简单的方法
Promise.prototype.all = function(promises) { let results = []; let promiseCount = 0; let promisesLength = promises.length; return new Promise(function(resolve, reject) { for (let val of promises) { Promise.resolve(val).then(function(res) { promiseCount++; // results.push(res); results[i] = res; // 当所有函数都正确执行了,resolve输出所有返回结果。 if (promiseCount === promisesLength) { return resolve(results); } }, function(err) { return reject(err); }); } }); };