Promise.all 接受一个 Promise 可迭代对象作为输入,返回一个 Promise。当所有的输入都成功时,则返回一个包含所有成功结果的数组;如果任何一个输入失败时,则返回失败结果。
本文将通过知识问答、手写实现、知识扩展几个环节,让你彻底摸透promise.all。
知识问答
1. 什么情况下可以使用Promise.all?
- 同时发起多个一步请求,等待所有的请求完成后再做出处理
- 多个异步任务之间相互独立,但需要等待所有的异步任务完成后再做出处理
2.Promise.all迭代参数中如果传入的不是promise对象,返回的是什么?
Promise.all会将其隐式转换为Promise对象,并将其视为已完成状态
3.Promise.all与Promise.race有什么区别?
Promise.all等待所有的Promise完成,而Promise.race只等待第一个完成的Promise。如果Promise.race中的任何一个Promise完成或失败,它将立即返回该Promise的结果或错误
4.能否手动取消Promise.all中的某个Promise?
标准的Promise API 不提供取消功能。一旦Promise开始执行,就不能被取消
5.如果Promise.all中的一个promise永远不resolve也不reject,会发生什么?
如果Promise.all中的一个Promise永远不解析(即,它是一个悬而未决的状态),那么Promise.all将永远等待,直到所有其他的Promise都完成。这可能导致应用程序挂起或超时。在这种情况下,可能需要设置超时机制来处理这种情况
手写实现Promise.all
1. 定义返回值
Promise.all 返回的结果也是一个 Promise,先自定义一个叫myAll的方法,直接返回一个promise。
/* 自定义myAll函数 */
Promise.myAll = function () {
const promise = new Promise();
return promise;
}
写个例子,模拟调用我们自己写的myAll方法
/* 定义几个接受参数 */
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 100);
});
/* 调用myAll函数 */
Promise.myAll([p1, p2, p3]).then((res) => {
console.log(res);
});
扫码加入前端交流群,期待你的加入!
2. 对空参数的处理
我们常常使用Promise.all 时,传入一个空数组作为参数,此时会直接返回成功状态,返回结果也为一个空数组。
但这里不能简单的通过判断接受参数的长度来处理这种特殊情况,因为接受的参数是一个可迭代对象,可迭代对象不只有数组一种,还包含 String 、Array、TypedArray、Map、Set 以及 NodeList 等。
如何判断可迭代对象的长度?
使用 for…of语句,for…of语句执行一个循环,该循环处理来自可迭代对象的值序列。因为可迭代对象都必须含有 @@iterator 方法
Promise.myAll = function (args) {
// 通过下面的promise,保存一份成功和失败的方法,用于后续的使用
let res, rej;
const promise = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
// 记录接受对象的数量
let count = 0;
// 定义返回结果
const result = [];
for (const iterator of args) {
count++;
}
// 如果没有可迭代内容,则直接返回成功
if (count === 0) res(result);
return promise;
};
3. 调用每个迭代对象
- 任何一个迭代对象失败时,则返回失败结果
- 全部迭代成功完成时,按照迭代顺序返回一个成功结果的数组
// 记录接受对象的数量
let count = 0;
// 记录完成的数量
let fulfilledCount = 0;
// 定义返回结果
const result = [];
for (const iterator of args) {
const index = count;
count++;
Promise.resolve(iterator).then((data) => {
// 把返回结果
result[index] = data;
fulfilledCount++;
// 完成数量等于总数量时,返回成功结果
if (count === fulfilledCount) res(result);
}, rej);
}
完成代码
Promise.myAll = function (args) {
// 通过下面的promise,保存一份成功和失败的方法,用于后续的使用
let res, rej;
const promise = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
// 记录接受对象的数量
let count = 0;
// 记录完成的数量
let fulfilledCount = 0;
// 定义返回结果
const result = [];
for (const iterator of args) {
const index = count;
count++;
Promise.resolve(iterator).then((data) => {
// 把返回结果
result[index] = data;
fulfilledCount++;
// 完成数量等于总数量时,返回成功结果
if (count === fulfilledCount) res(result);
}, rej);
}
// 如果没有可迭代内容,则直接返回成功
if (count === 0) res(result);
return promise;
};
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 100);
});
Promise.myAll([p1, p2, p3]).then((res) => {
console.log(res);
});
// [ 3, 1337, 'foo' ]
知识扩展
1. 非promise对象的隐式转换
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 100);
});
const p4 = undefined;
const p5 = {};
const p6 = null;
const p7 = true;
const promiseList = [p1, p2, p3, p4, p5, p6, p7];
Promise.all(promiseList).then((res) => {
console.log(res);
});
// [ 3, 1337, 'foo', undefined, {}, null, true ]
2. 什么是可迭代对象
在JS中,可迭代对象是指那些实现了Symbol.iterator方法的对象。
这种类型的对象允许开发者自定义遍历的行为,从而使得不仅仅是内置的数据结构(如数组、字符串)可以迭代,自定义的对象也可以遍历。
- 实现Symbol.iterator方法:为了使一个对象成为可迭代对象,它必须实现Symbol.iterator方法。这个方法返回一个迭代器,即具有next()方法的对象。
- 使用for…of循环:可以使用for…of循环来遍历可迭代对象。在每次迭代中,for…of会调用迭代器的next()方法,获取下一个值。
- 自定义迭代行为:通过定义Symbol.iterator方法,开发者可以自定义迭代的行为,例如决定如何生成序列中的下一个值。
- 内置的可迭代对象:除了自定义对象,JavaScript中的许多内置对象如数组、字符串、Map、Set等都是可迭代的。
写在最后
欢迎大家访问我的个人网站:www.dengzhanyong.com
扫码加入前端交流群,期待你的加入!