在我们舒服的在代码中使用 await 的之前,我们需要认识到一些我们不能做的:
- 在没有 async 标注的函数中使用 await;
- 在顶层使用 await;
第一个我们在之前的文章已经讨论过,那第二个我们接下来介绍:
async function wait(message, time) {
return new Promise((resolve) => setTimeout(resolve(message), time));
}
await wait ("hello", 2000); // SyntaxError: await is only allows inside an async function
我们可以重写使其正常工作:
async function wait(message, time) {
return new Promise((resolve) => setTimeout(resolve(message), time));
}
async function execute() {
const message = await wait ("hello", 2000);
console.log(message); // hello (after 2000 ms)
}
execute();
意外的使代码同步
async/await 最大的为题在于 await 很容易被滥用,我们多数情况下是系统代码异步执行使得代码更高效。
为了帮助我们理解这个问题,我来举一个 promise 的例子,然后把它转为 async/await 接着改正它:
const sayGreeting = (name, time) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`Hello ${name}`);
}, time);
})
}
sayGreeting("Parwinder", 1000)
.then((data) => {
console.log(data); // "Hello Parwinder" after 1 second
return sayGreeting("Lauren", 2000);
})
.then((data) => {
console.log(data); // "Hello Lauren" after 2 seconds
return sayGreeting("Robert", 500);
})
.then((data) => {
console.log(data); // "Hello Robert" after half a second
return sayGreeting("Eliu", 2000);
})
.then((data) => {
console.log(data); // "Hello Eliu" after 2 seconds
return sayGreeting("George", 1500);
})
.then((data) => {
console.log(data); // "Hello George" after 1.5 seconds
})
上面的例子是在指定时间后想某个人打招呼,Promise 避免了 callback 的回调地狱,但依旧存在一层回调。
我们可以使用 await 来重写:
const sayGreeting = (name, time) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`Hello ${name}`);
}, time);
})
}
const main = async () => {
let a = await sayGreeting("Parwinder", 1000);
console.log(a); // "Hello Parwinder" after 1 second
a = await sayGreeting("Lauren", 2000);
console.log(a); // "Hello Lauren" after 2 seconds
a = await sayGreeting("Robert", 500);
console.log(a); // "Hello Robert" after half a second
a = await sayGreeting("Eliu", 2000);
console.log(a); // "Hello Eliu" after 2 seconds
a = await sayGreeting("George", 1500);
console.log(a); // "Hello George" after 1.5 seconds
}
main();
没有了 then 的回调且更容易阅读,目前为止我们把 promise 改为了 async/await 而且代码看上去更好,错误在哪里呢?
多数情况下,我们期望异步是并行执行。每次在 main 函数中添加一个 await 就会阻止代码向下执行直到 promise 完成。我们可以同时执行多个 promise 且取得执行结果。
我们使用 Promise.all 与 async/await 一起使得代码更高效:
const sayGreeting = (name, time) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`Hello ${name}`);
}, time);
})
}
const main = async () => {
const a = sayGreeting("Parwinder", 1000);
const b = sayGreeting("Lauren", 2000);
const c = sayGreeting("Robert", 500);
const d = sayGreeting("Eliu", 2000);
const e = sayGreeting("George", 1500);
const [greeting1, greeting2, greeting3, greeting4, greeting5] = await Promise.all([a, b, c, d, e]);
// all promises in promise.all
console.log(greeting1, greeting2, greeting3, greeting4, greeting5)
}
main();
我们做了什么:
- 我们把 promise 存在变量里,而不是等待 promise 完成;
- 我们创建了一个巨大的 promise 集合;
- 我们 await 这个 Promise.all 而不是独立的 promise;
- Promise.all 同时执行所有的 promise ,并等待所有结果返回并赋值给对应的变量;
- 打印输出。
希望可以提高你使用 async/await 的能力。