异步函数策略
1、实现sleep
`async` function sleep(delay) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, delay);
});
}
async function test() {
const t0 = Date.now();
await sleep(1000);
console.log(Date.now() - t0);
}
test();
// 1000
2、利用平行执行
如果使用await时不留心,则很可能错过平行加速的机会
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) =>
setTimeout(() => {
console.log(`${id} finished`);
resolve();
}, delay)
);
}
async function foo() {
const t0 = Date.now();
await randomDelay(0);
await randomDelay(1);
await randomDelay(2);
await randomDelay(3);
await randomDelay(4);
console.log(`${Date.now() - t0}ms elapsed`);
}
foo();
// 0 finished
// 1 finished
// 2 finished
// 3 finished
// 4 finished
// 3795ms elapsed
用for循环重写
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) =>
setTimeout(() => {
console.log(`${id} finished`);
resolve();
}, delay)
);
}
async function foo() {
const t1 = Date.now();
for (let i = 0; i < 5; i++) {
await randomDelay(i);
}
console.log(`${Date.now() - t1}ms elapsed`);
}
foo();
// 0 finished
// 1 finished
// 2 finished
// 3 finished
// 4 finished
// 3462ms elapsed
就算这些期约之间没有依赖,异步函数也会依次暂停,等待每个超时完成。这样可以保证执行顺序,但总执行时间会变长
如果顺序不是必须保证的,那么可以先一次性初始化所有期约,然后再分别等他们的结果,比如
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) =>
setTimeout(() => {
console.log(`${id} finished`);
resolve();
}, delay)
);
}
async function foo() {
const t1 = Date.now();
const p0 = randomDelay(0);
const p1 = randomDelay(1);
const p2 = randomDelay(2);
const p3 = randomDelay(3);
const p4 = randomDelay(4);
await p0;
await p1;
await p2;
await p3;
await p4;
setTimeout(console.log, 0, `${Date.now() - t1}ms elapsed`);
}
foo();
// 0 finished
// 2 finished
// 3 finished
// 1 finished
// 4 finished
// 993ms elapsed
用数组和for循环再包装一下就是
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) =>
setTimeout(() => {
console.log(`${id} finished`);
resolve();
}, delay)
);
}
async function foo() {
const t0 = Date.now();
const promises = Array(5)
.fill(null)
.map((_, index) => randomDelay(index));
for (const p of promises) {
await p;
}
console.log(`${Date.now() - t0}ms elapsed`);
}
foo();
// 2 finished
// 1 finished
// 4 finished
// 3 finished
// 0 finished
// 964ms elapsed
注意,虽然期约没有按照顺序执行,但await按照顺序收到了每个期约的值
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) =>
setTimeout(() => {
console.log(`${id} finished`);
resolve(id);
}, delay)
);
}
async function foo() {
const t0 = Date.now();
const promises = Array(5)
.fill(null)
.map((_, index) => randomDelay(index));
for (const p of promises) {
console.log(`awaiting ${await p}`);
}
console.log(`${Date.now() - t0}ms elapsed`);
}
foo();
// 3 finished
// 2 finished
// 4 finished
// 1 finished
// 0 finished
// awaiting 0
// awaiting 1
// awaiting 2
// awaiting 3
// awaiting 4
// 923ms elapsed
3、串行执行期约
function addTwo(x) {
return x + 2;
}
function addThree(x) {
return x + 3;
}
function addFour(x) {
return x + 4;
}
async function addTen(x) {
for (const fn of [addTwo, addThree, addFour]) {
x = await fn(x);
}
return x;
}
addTen(10).then(console.log); // 19