async 和 await 有可能陷入困境,不是语法的问题,而是使用者书写不当造成的
// 现代前端代码
(async () => {
const pizzaData = await getPizzaData() // async call
const drinkData = await getDrinkData() // async call
const chosenPizza = choosePizza()
const chosenDrink = chooseDrink()
await addPizzaToCart(chosenPizza) // async call
await addDrinkToCart(chosenDrink) // async call
orderItems() // async call
})()
-
语法本身并没有问题,当
pizzaData
和drinkData
依赖的时候,顺序的 await 会最多让执行时间增加一倍的getPizzaData
函数时间,因为getPizzaData
与getDrinkData
应该并行执行 -
回到吐槽较多的回调地狱,虽然代码丑,但是不至于两行代码执行有阻塞
-
语法简化却带来性能问题,直接影响到用户体验
-
正确做法应该是先同时执行函数,然后再 await 返回值,这样可以并行执行异步函数
(async () => { const pizzaPromise = selectPizza(); const drinkPromise = selectDrink(); await pizzaPromise await drinkPromise })
-
或者使用
Promise.all
,不过可能会让你的代码性能降低(async () => { Promise.all([selectPizza(), selectDrink()]).then(orderItems) // async call })
-
-
async/ await 被滥用的思考:语法糖带来的便捷 && 牺牲了部分功能
-
解决问题: 回调地狱
a(() => { b(() => { c(); }) }) // to this: await a(); await b(); await c();
- 虽然层级一致,但是逻辑还是存在嵌套关系,隐形转换有时候会被忽略导致语法糖的滥用
-
思考逻辑下的回调场景: 两层同级同步代码嵌套异步代码时的优化
// a -> b 存在依赖关系 b -> d 存在依赖关系, a / d 可以并发(同步)执行 a(() => { b(); }) c(() => { d(); }) // 翻译 await a(); await b(); await c(); await d(); // 优化 const resA = a(); const resC = c(); await resA; b(); await resC; d(); // 相当于完全隔离状态 (async () => { await a(); b(); })(); (async () => { await c(); d(); })(); // Promise.all async function ab() { await a(); b(); } async function cd() { await c(); d(); } Promise.all([ab(), cd()]);
- Async/await 写完需要反思一下有没有依赖的异步关系,虽然可读性上去了,但是比回调地狱的性能更低
- 同步与 await 混杂在一起需要正确使用,必要情况可以使用回调,对增强代码可读性有一定的帮助
- async/ await 回调地狱提醒我们不要过度依赖新特性,否则会对代码执行效率下降,影响用户体验,同时也不要过度利用新特性修复新特性带来的问题,这样反而导致代码可读性的下降
- 决定代码质量的是思维,并非框架或语法, async/await 虽然好,但是也要适度使用。