串行执行多个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);