关灯
开启左侧

怎样处理async/await浪费性能问题

[复制链接]
老蚊子 发表于 2019-1-23 09:08:39 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
 
这次给大家带来怎样处理async/await浪费性能问题,处理async/await浪费性能问题的注意事项有哪些,下面就是实战案例,一起来看一下。


前言
async/await是什么

async/await可以说是co模块和生成器函数的语法糖。用更加清晰的语义解决js异步代码。

熟悉co模块的同学应该都知道,co模块是TJ大神写的一个使用生成器函数来解决异步流程的模块,可以看做是生成器函数的执行器。而async/await则是对co模块的升级,内置生成器函数的执行器,不再依赖co模块。同时,async返回的是Promise。

从上面来看,不管是co模块还是async/await,都是将Promise作为最基础的单元,对Promise不很了解的同学可以先深入了解一下Promise。

async/await 写着很爽,不过要注意这些问题。

async/await 让我们摆脱了回调地狱,但是这又引入了 async/await 地狱的问题。


什么是 async/await 地狱
在 Javascript 中进行异步编程的时候,人们总是使用很多 await 语句,很多时候我们的语句并不需要依赖于之前的语句,这样就会导致性能问题。

async/await 地狱的例子

我们试着写一个购买披萨和饮料的程序:

  1. (async () => {

  2. const pizzaData = await getPizzaData() // async call

  3. const drinkData = await getDrinkData() // async call

  4. const chosenPizza = choosePizza() // sync call

  5. const chosenDrink = chooseDrink() // sync call

  6. await addPizzaToCart(chosenPizza) // async call

  7. await addDrinkToCart(chosenDrink) // async call

  8. orderItems() // async call

  9. })()
复制代码
这段代码运行没有问题。但是不是一个好的实现,因为这增加了不必要的等待。


说明


我们已经将我们的代码封装在异步 IIFE 中,按照下面的顺序执行:
得到披萨名单
获取饮料列表
从列表中选择一个披萨
从列表中选择一种饮料
将选中的披萨加入购物车
将选择的饮品加入购物车
订购购物车中的物品


问题


这里有个问题为什么从列表中选择披萨这个动作要等待获取饮料列表?这两个是没什么关联的操作。其中的关联操作有两组:


获取披萨列表 -》 选择披萨 -》 选择披萨加入购物车


获取饮料列表 -》 选择饮料 -》 选择饮料加入购物车

这两组操作应该是并发执行的。

再来看一个更差的例子

这个 Javascript 代码片段将购物车中的商品并发出订购请求。
  1. async function orderItems() {

  2. const items = await getCartItems() // async call

  3. const noOfItems = items.length

  4. for(var i = 0; i < noOfItems; i++) {

  5. await sendRequest(items[i]) // async call
  6. }
  7. }
复制代码
这种情况 for 循环必须等待 sendRequest() 函数完成才能继续下一次迭代。但是,我们并不需要等待。我们希望尽快发送所有请求。然后我们可以等待所有请求完成。


现在你应该已经对 async/await 地狱有跟多的了解,现在我们再来考虑一个问题


如果我们忘记 await 关键字会怎么样?


如果在调用异步函数忘记使用 await,这意味着执行该功能不需要等待。异步函数将直接返回一个 promise,你可以稍后使用。


  1. (async () => {

  2. const value = doSomeAsyncTask()

  3. console.log(value) // an unresolved promise

  4. })()
复制代码
或者是程序不清楚你想要等待函数执行完,直接退出不会完成这个异步任务。所以我们需要使用 await 这个关键字。

promise 有一个有趣的属性,你可以在某行代码中获取 promise,然后在其他地方中等待它 resolve,这是解决 async/await 地狱的关键。
  1. (async () => {

  2. const promise = doSomeAsyncTask()

  3. const value = await promise

  4. console.log(value) // the actual value

  5. })()
复制代码
如你所见 doSomeAsyncTask 直接返回一个 Promise 同时这个异步函数 doSomeAsyncTask 已经开始执行,为了得到 doSomeAsyncTask 的返回值,我们需要 await 来告诉

应该如何避免 async/await 地狱

首先我们需要知道哪些命名是有前后依赖关系的。

然后将有依赖关系的系列操作进行分组合并成一个异步操作。

同时执行这些异步函数。

我们来重写这写例子:

  1. async function selectPizza() {

  2. const pizzaData = await getPizzaData() // async call

  3. const chosenPizza = choosePizza() // sync call

  4. await addPizzaToCart(chosenPizza) // async call

  5. }

  6. async function selectDrink() {

  7. const drinkData = await getDrinkData() // async call

  8. const chosenDrink = chooseDrink() // sync call

  9. await addDrinkToCart(chosenDrink) // async call

  10. }

  11. (async () => {

  12. const pizzaPromise = selectPizza()

  13. const drinkPromise = selectDrink()

  14. await pizzaPromise

  15. await drinkPromise

  16. orderItems() // async call

  17. })()

  18. // Although I prefer it this way

  19. (async () => {

  20. Promise.all([selectPizza(), selectDrink()].then(orderItems) // async call

  21. })()
复制代码
我们将语句分成两个函数。在函数内部,每个语句都依赖于前一个语句的执行。然后我们同时执行这两个函数 selectPizza()和selectDrink() 。

在第二个例子中我们需要处理未知数量的 Promise。处理这个问题非常简单,我们只需要创建一个数组将所有 Promise 存入其中,使用 Promise.all() 方法并行执行:

  1. async function orderItems() {

  2. const items = await getCartItems() // async call

  3. const noOfItems = items.length

  4. const promises = []

  5. for(var i = 0; i < noOfItems; i++) {

  6. const orderPromise = sendRequest(items[i]) // async call

  7. promises.push(orderPromise) // sync call

  8. }

  9. await Promise.all(promises) // async call

  10. }
复制代码
以上就是怎样处理async/await浪费性能问题的详细内容。






 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


1关注

13粉丝

75帖子

排行榜
关闭

站长推荐上一条 /1 下一条

官方微信

全国服务热线:

400-0708-360

公司地址:国家西部信息安全产业基地(成都市高新区云华路333号)

邮编:610000    Email:2908503813@qq.com

Copyright   ©2015-2016  EOIT论坛Powered by©Discuz!    ( 蜀ICP备11000634号-7 )