【问题标题】:Async Vue lifecycles异步 Vue 生命周期
【发布时间】:2021-01-16 18:31:33
【问题描述】:

我的 Vue.js 应用程序出现以下情况:

data() {
   return {
      data: []
   }
},

async created() {
   console.log('before async call')
   try {
      // async call ...
      console.log('after async call')
      this.data = // data from api call
   } catch (err) {
      // handle err
   }
},

mounted() {
   console.log('mounted')
   init(this.data)
}

当我运行代码时,我得到:

before async call
mounted
after async call

因此,作为 mount 中的类构造函数的 init 方法被调用时使用一个空数组,而不是来自 API 调用的数据。我想要的是同步执行事情并且在数据可用之前不执行挂载。我理解上面的问题是在包含异步代码的情况下Vue如何执行生命周期,但是你如何解决这样的问题呢?

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    如果我是你,我会将所有逻辑放在 mountedcreated 挂钩中。如果出于某种原因您需要等到mount 才能让您的代码工作,请获取数据并在mounted 中初始化:

    async mounted() {
       try {
          // async call ...
          console.log('after async call')
          this.data = await // data from api call
          init(this.data)
       } catch (err) {
          // handle err
       }
    }
    

    createdmounted 之间拆分代码时,您几乎无法获得任何性能提升。

    不过,如果出于某种原因您确实需要将它们放在不同的钩子中,您可以将 data 存储在 promise 中:

    async created() {
       console.log('before async call')
       try {
          // async call ...
          console.log('after async call')
          this.data = fetch('whatever') // now this.data is a promise
       } catch (err) {
          // handle err
       }
    },
    
    async mounted() {
       console.log('mounted')
       init(await this.data)
    }
    

    这应该可行,但我认为不值得麻烦。

    作为对可能阅读此内容的任何人的澄清:您可以在 vue 生命周期挂钩中使用 async/await 以便在其中编写代码以等待承诺等。但是,这不会使 Vue 实际上等待生命周期本身:因此您可以在created 的异步代码之前运行的mounted 代码结束。 Vue 不等待异步生命周期这一事实并不意味着在其中放置异步/等待代码是不好的。

    【讨论】:

      【解决方案2】:

      async Vue 中的生命周期是一种误导性语法。

      每个 Vue 生命周期只是一个触发器,用于运行您在特定时间放入的任何代码。

      但是 Vue 不会等待 promise 解决并保留所有其他内容(与组件的生命周期相关),直到它发生。实际上,您所做的只是延迟执行您放置在生命周期中的代码,直到某些承诺解决为止。

      为了让您更好地理解正在发生的事情,以下语法是等效的:

      async created() {
        const data = await fetchSomeData(); 
        // rest of code depending on `data`
      }
      

      等价物:

      created() {
        fetchSomeData().then(data => {
          // rest of code depending on `data`
        });
      }
      

      由于async 生命周期是一种误导性语法,因此在大型团队开发的应用程序中通常不鼓励使用它,而支持.then() 语法。这是为了避免在代码实际运行时因误解而产生的小错误。例如,如果新开发人员将一些代码放入 async 挂钩中(没有仔细查看挂钩中的其余代码),则代码可能会比预期运行得晚,除非放在任何 await 之前。


      要修复您要修复的任何错误,只需将在实际 data 解析为 if(内部组件)或 v-if(内部模板)之前无法呈现的内容包装起来。

      典型用法示例:

      computed: {
        someComputed() {
          if (this.data.length) {
            // returned when data has length
            return something
          }
          // returned when data has no length
          return somethingElse
        }
      }
      

      或:

      <div v-if="data.length">
         <!-- markup depending on actual data... -->
      </div>
      <div v-else>
         loading...
      </div>
      

      注意:上面的computed 将自动响应data 长度的变化(不需要watch),因为computed 属性会在其内部反应引用更改值时重新运行。正如您所料,它们会根据它们重新计算/重新渲染任何内容。 &lt;v-if&gt; 也是如此。在内部,它们都使用所谓的 Vue 的“注入和反应性”

      【讨论】:

        猜你喜欢
        • 2017-07-06
        • 2021-06-12
        • 2020-04-06
        • 1970-01-01
        • 1970-01-01
        • 2020-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多