出现原因
出现这个问题主要是业务当中碰到了,基于这个问题研究了一下问题出现的原因以及解决的方法。
本质是想先进行循环调用接口,然后执行下面的操作,但是发现不同的写法会导致执行顺序有问题。
forEach+async/await例子
function example1() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
promises.forEach(async (promise) => {
let result = await promise;
console.log(result);
});
console.log(4);
console.log(5);
}
example1();
先执行console.log(4),这是因为JavaScript的异步处理机制。在你的代码中,forEach循环中的每个Promise都被标记为async,这意味着它们将在后台运行,而主线程将继续执行后面的代码。因此,console.log(4)和console.log(5)将首先执行。
当你在JavaScript中使用async/await时,你实际上是在创建一个新的Promise。这个Promise在后台运行,而主线程继续执行其他代码。当Promise完成时,它的结果将被返回,但这可能发生在主线程已经执行了其他代码之后。
所以在例子中,forEach循环中的Promise可能还在运行,而主线程已经执行了console.log(4)和console.log(5)。这就是为什么你看到4和5首先被打印出来,然后是1、2和3。
function example1() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
promises.forEach(async (promise) => {
// let result = await promise;
console.log(promise);
//console.log(await promise);//4 5 1 2 3
});
console.log(4);
console.log(5);
}
example1();
Promise的构造函数是同步的,Promise.then是异步的,加上await,实际上是调用了then方法,所以会先执行同步任务,后执行Promise.then这个微任务。所以打印await promise是4 5 1 2 3
for await of例子
async function example() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
for await (let result of promises) {
console.log(result);
}
console.log(4);
console.log(5);
}
example();
在这个例子中,使用了for await...of循环,这是一种特殊的循环,用于处理异步操作,特别是Promise。
for await...of循环会等待每个Promise解析,然后打印结果。这意味着它会按照顺序打印1,2,3。只有当所有的Promise都解析完毕,循环才会结束,然后才会执行并打印4和5。
所以,执行顺序将会是:1,2,3,4,5。
第二个例子与第一个例子不同,因为在第一个例子中,使用的是forEach循环和async函数,这会导致Promise在后台运行,而主线程继续执行其他代码。但在这个例子中,for await...of循环确保了在继续执行其他代码之前,所有的Promise都已经解析完毕。
两者的区别就在写法上面,如果把第二种情况做一个改写,也会出现第一种情况的结果。
function example() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
for (let result of promises) {
async function log() {
console.log(await result);
}
log();
}
console.log(4);
console.log(5);
}
example();
Promise.all+map+async/await写法
function example1() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
Promise.all(
promises.map(async (promise) => {
let result = await promise;
console.log(result);
})
).then(() => {
console.log(4);
console.log(5);
});
}
example1();
reduce写法
async function example1() {
let promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
];
await promises.reduce( (l,item) => {
return l.then(()=>{
item.then(res=>{
console.log(res);
})
return item
})
},Promise.resolve());
console.log(4);
console.log(5);
}
example1();
在 JavaScript 中,reduce
函数用于数组的累积操作,而传递给 reduce
的第二个参数是初始值。如果你传递了 Promise.resolve()
作为初始值,那么 reduce
就可以用于在异步操作中进行累积。
在上面的例子中,reduce
中的初始值是 Promise.resolve()
。每次迭代都返回一个 Promise,该 Promise 在异步操作完成后调用 resolve
。这确保了数组中的每个元素都在前一个异步操作完成后处理。
这种方式可以确保异步操作按顺序执行,并且是 reduce
的一种常见用法,特别是当你需要对异步操作的结果进行累积时。这种写法适用于需要按照一定顺序处理一组异步任务的场景。