zoukankan      html  css  js  c++  java
  • 你可能忽略的 async/await 问题

    一个例子

    下面是一个常见的 vue 代码片段:

     async initStore(query) {
        await this.getConfig();
        await this.getUser();
        await this.checkRussianContext(query);
    
        await this.getBasket(this.$store.state.config.selectedCurrency),
    
        await this.$store.dispatch('options/fetchOptions', {
          basket : this.$store.state.basket,
        });
     },

    上面的代码中,每一行都会 等待上一行的结果返回后才会执行。比如其中的 getUser 会等待 getConfig 数据返回之后才会执行。

    当看到这段代码时,脑子里应该注意到以下几点:

    • 如果某一行的执行不需要上面一行的数据怎么办?为什么阻塞代码使整个应用程序变慢呢?
    • 我们可不可以让所有不相关的方法一起执行?比如使用 Promise.all?
    • 能否让相关的方法使用 then 进行链式调用来避免阻塞剩余代码?

    本篇文章的重点就是通过分析 async/await 可能引发的问题,帮你找到 代码的坏味道

    无关的请求请并行执行

    让我们来看一些具体的数据下的情况。

    下面是示例代码:

    const getUserData = async () => {
      // 获取一张随机的狗狗图片作为头像
      const res = await fetch('https://dog.ceo/api/breeds/image/random')
      const { message } = await res.json()
    
      // 获取随机生成的用户信息
      const user = await fetch('https://randomuser.me/api/')
      const { results } = await user.json()
    
      // ...
    }

    上面的代码在 fast 3G (使用 Chrome 开发者工具)下执行 100 次,平均执行时间为 1231.10ms

    但是很显然,第二个请求并不需要第一个请求的结果,所以我们修改成以下代码并执行 100 次:

    const getUserDataFaster = async () => {
      // 两个请求并行执行
      const [res, user] = await Promise.all([
        fetch('https://dog.ceo/api/breeds/image/random'), 
        fetch('https://randomuser.me/api/')
      ])
      const [{ message }, { results }] = await Promise.all([res.json(), user.json()])
    
      // ...
    }

    我们得到的平均执行时间为 612.50ms,几乎节省了一半时间。

    划重点:尽可能地把查询请求并行执行。

    可以用这个 codepen 中的代码体验

    广州设计公司https://www.houdianzi.com 我的007办公资源网站https://www.wode007.com

    无关的代码你不必等

    再来例子:

    async initStore(query) {
       await Promise.all([
         this.getConfig(),
         this.getUser(),
         this.checkRussianContext(query)
       ])
    
       await this.getBasket(this.$store.state.config.selectedCurrency),
    
       await this.$store.dispatch('options/fetchOptions', {
         basket : this.$store.state.basket,
       });
    
       await initBooking()
    },

    前面的 3 个请求是并行执行的,而下一段代码依赖了前面获取的数据,所以需要在其后执行,但是你有没有发现其中的问题?

    initBooking 这个小可怜只能等到 getBasket 和 fetchOptions 完成之后才能执行,尽管它不需要这两个方法的任何数据。

    一个简单的解决办法是将 await 换成 .then 来使用:

    关于这个用法可以看开头的另一篇文章
    async initStore(query) {
      await Promise.all([
        this.getConfig(),
        this.getUser(),
        this.checkRussianContext(query)
      ])
    
      this.getBasket(this.$store.state.config.selectedCurrency).then(async () => {
        await this.$store.dispatch('options/fetchOptions', {
          basket : this.$store.state.basket,
        });
      })   
    
      await initBooking()
    },

    这样的话,getBasket 和 initBooking 都可以并行执行了。

  • 相关阅读:
    批量新增百万条数据 十百万条数据
    sqlserver 组内排序
    EF ++属性会更新实体
    Entity Framework Core: A second operation started on this context before a previous operation completed
    abp Cannot access a disposed object. A common cause of this error is disposing
    abp xunit Can not register IHostingEnvironment. It should be a non-abstract class. If not, it should be registered before.”
    hangfire enqueued but not processing(hangfire 定时任务入队列但不执行)
    EF 更新实体 The instance of entity type 'BabyEvent' cannot be tracked because another instance
    datatable to entiy list 不支持可空类型和枚举类型
    webapi 设置不显示接口到swaggerUI
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13847346.html
Copyright © 2011-2022 走看看