Skip to main content

串行执行多个Promise

先实现一个延迟函数

一个封装的延迟函数,然后一个装有 3,4,5 的数组,需求就是在开始执行时依次等待 3, 4, 5 秒,并在之后打印对应输出

function delay(time) {
return new Promise((resolve, reject) => {
console.log(`wait ${time}s`);
setTimeout(() => {
console.log('execute');
resolve();
}, time * 1000);
});
}

const arr = [3, 4, 5];

期望结果

wait 3s // 等待3s

execute
wait 4s // 等待4s

execute
wait 5s // 等待5s

execute

方法一 reduce

前一个函数 resolve 之后执行下一个 promise

arr.reduce((s, v) => {
return s.then(() => delay(v));
}, Promise.resolve());

方法二 async + 循环 + await

forEach 循环不可以,可以理解成 forEach 的回调函数本身就是异步函数,放入调用栈,结束本次遍历

(async function() {
for (const v of arr) {
await delay(v);
}
})();

方法三 普通循环

方式 1 的本质是使用一个中间变量(上一次执行结果)来保存链式 Promise, 那我们举一反三, 换别的循环也可以实现

let p = Promise.resolve();
for (const i of arr) {
p = p.then(() => delay(i));
}

方法四 递归

其中洋葱模型来自于 koa-compose 库

function dispatch(i, p = Promise.resolve()) {
if (!arr[i]) return Promise.resolve();
return p.then(() => dispatch(i + 1, delay(arr[i])));
}
dispatch(0);

方法五 for await of

for await of 和 for of 规则类似,只需要实现一个内部[Symbol.asyncIterator]方法即可 先创建出一个可异步迭代对象,然后丢到 for await of 循环即可

function createAsyncIterable(arr) {
return {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < arr.length) {
return delay(arr[this.i]).then(() => ({
value: this.i++,
done: false,
}));
}

return Promise.resolve({ done: true });
},
};
},
};
}

(async function() {
for await (i of createAsyncIterable(arr)) {
}
})();

方法六 generator

function* gen() {
for (const v of arr) {
yield delay(v);
}
}

function run(gen) {
const g = gen();

function next(data) {
const result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data) {
next(data);
});
}

next();
}

run(gen);