我的 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
因此,init 方法是mounted 中的类构造函数,它被调用为空数组,而不是来自API 调用的数据。我想要的是同步执行事情,并且在数据可用之前不执行挂载。我知道上面的问题是当包含异步代码时Vue如何执行生命周期,但是你如何解决这样的问题?
答案 0 :(得分:2)
如果我是你,我会将所有逻辑放在 mounted
或 created
钩子中。如果由于某种原因您需要等到 mount
才能让您的代码工作,请获取数据并在 mounts 中对其进行初始化:
async mounted() {
try {
// async call ...
console.log('after async call')
this.data = await // data from api call
init(this.data)
} catch (err) {
// handle err
}
}
在 created
和 mounted
之间拆分代码在性能方面几乎没有任何好处。
不过,如果由于某种原因你真的需要将它们放在不同的钩子中,你可以将 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 实际上等待生命周期本身:因此您可以在 mounted
的异步代码之前运行 created
代码。 Vue 不等待异步生命周期这一事实并不意味着将异步/等待代码放入其中是不好的。
答案 1 :(得分:2)
async
生命周期是一种误导性的语法。
每个 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
属性会重新运行每当它们的内部反应引用改变值时。正如您所期望的,它们会根据它们重新计算/重新渲染任何内容。 <v-if>
也是如此。在内部,它们都使用所谓的 Vue 的“注入和反应性”。