在JS中forEach在处理异步任务的时候是并行处理的:
const count = (item) => {
return new Promise((resolve) => {
if (typeof item === 'number') {
setTimeout(() => {
console.log(item);
resolve();
}, 500);
} else {
setTimeout(() => {
console.log(item);
resolve();
}, 1000);
}
})
}
// forEach
let arr = [1, 'a', 'b', 'c', 2];
arr.forEach(async item => {
const ret = await count(item);
});
// 1
// 2
// a
// b
// c
// for
(async function test() {
for (let i = 0; i < arr.length; i++) {
await count(arr[i]);
}
})();
// for ... of
(async function test() {
for (let x of arr) {
const res = await count(x)
}
})();
基于这个特性,我们可以在一些并发请求的时候使用,在手写 Promise.all 等类似方法的时候也可以使用forEach来完成。
Bromise.all = (fns) => {
return new Bromise((resolve, reject) => {
let count = 0;
let res = [];
fns.forEach((fn, index) => {
fn.then((val) => {
count++;
res[index] = val;
if (count === fns.length) {
resolve(res);
}
}, (reason) => {
reject(reason);
});
});
});
}
Bromise.race = (fns) => {
return new Bromise((resolve, reject) => {
fns.forEach((fn) => {
fn.then(resolve, reject);
})
})
}
Bromise.allSettled = (promiseList) => {
return new Bromise((resolve, reject) => {
const len = promiseList.length;
let count = 0;
let result = [];
if (len === 0) return resolve(result);
promiseList.forEach((promise, index) => {
promise.then((value) => {
count++;
result[index] = {
status: 'fulfilled',
value,
};
if (count === len) resolve(result);
}, (reason) => {
count++;
result[index] = {
status: 'rejected',
reason,
};
if (count === len) resolve(result);
})
})
})
}
Bromise.any = (promiseList) => {
const len = promiseList.length;
let rejectArr = [];
return new Bromise((resolve, reject) => {
promiseList.forEach((promise, index) => {
promise.then((res) => {
resolve(res);
}).catch((err) => {
rejectArr[index] = err;
if (rejectArr.length === len) {
reject(new Error(rejectArr));
}
});
});
});
}