在等待承诺完成时无法在 Vue.js 中获取 DOM 更新
Trouble getting DOM update in Vue.js while waiting for promise to complete
我不是很精通 JS promises,虽然我通常知道足够危险。我正在研究处理搜索 this.data()
中存在的大型数据对象的 Vue 方法 - 通常当我通过 axios 发出异步请求时,同样的格式工作正常但在这种情况下我必须手动创建一个承诺来获得期望的行为。这是代码示例:
async searchPresets() {
if (this.presetSearchLoading) {
return
}
this.presetSearchLoading = true; // shows spinner
this.presetSearchResults = []; // removes old results
this.selectedPresetImports = []; // removes old user sections from results
// Need the DOM to update here while waiting for promise to complete
// otherwise there is no "loading spinner" feedback to the user.
const results = await new Promise(resolve => {
let resultSet = [];
for (var x = 0; x < 10000; x++) {
console.log(x);
}
let searchResults = [];
// do search stuff
resolve(searchResults);
});
// stuff after promise
}
事实是,promise 之后的内容可以正常工作。它在执行之前等待解决方案,并按应有的方式接收正确的搜索结果数据。
问题是 DOM 在发送 promise 时没有更新,所以 UI 只是坐在那里。
有人知道我做错了什么吗?
尝试 $nextTick()
:
Vue 2.1.0+:
const results = await this.$nextTick().then(() => {
let resultSet = []
for (var x = 0; x < 10000; x++) {
console.log(x)
}
let searchResults = []
// do search stuff
return searchResults
});
任何 Vue:
const results = await new Promise(resolve => {
this.$nextTick(() => {
let resultSet = []
for (var x = 0; x < 10000; x++) {
console.log(x)
}
let searchResults = []
// do search stuff
resolve(searchResults)
})
})
Vue 将查找数据更改并将它们收集到一个数组中,以判断 DOM 之后是否需要重新渲染。这意味着 Vue 中的一切都是事件(数据)驱动的。您的函数只定义了没有数据绑定到 V-DOM 的行为。因此 Vue 引擎将不执行任何操作,因为它们的依赖数据集中没有任何更改。
我看到您的 Promise 函数将解析对变量的响应 "searchResults"。如果您的 DOM 使用该变量,Vue 引擎将在 Promise 完成后收集更改。您可以在 "data()" 中放置一个 属性 并将其绑定到 DOM.
例如:
<span v-for="(res, key) in searchResults" :key="key">
{{ res.name }}
</span>
...
<script>
export default {
...
data () {
return { searchResults: [] }
},
...
}
</script>
所以当我说 "I'm not super versed in JS promises though I generally know enough to be dangerous.".
时,我好像已经说完了
我很感激有人尝试帮助我解决这个问题,但事实证明,做出承诺并不会本质上使它成为异步的。这是我的错误。问题不在于 Vue 没有更新 DOM,问题在于 promise 代码正在同步执行并阻塞 - 因此因为执行实际上从未停止等待,Vue 没有更新 [=21= 的权限].
一旦我将我的承诺代码包装在 setTimout(() => { /* all code here then: */ resolve(searchResults); }, 200);
中,一切都开始工作了。我想设置的超时允许执行停止足够长的时间让 vue 根据我之前的数据更改来更改 dom。该脚本在运行时在技术上仍然会阻止 UI,但至少我的加载程序在此过程中正在旋转,这足以满足我在这里所做的事情。
参见:
我不是很精通 JS promises,虽然我通常知道足够危险。我正在研究处理搜索 this.data()
中存在的大型数据对象的 Vue 方法 - 通常当我通过 axios 发出异步请求时,同样的格式工作正常但在这种情况下我必须手动创建一个承诺来获得期望的行为。这是代码示例:
async searchPresets() {
if (this.presetSearchLoading) {
return
}
this.presetSearchLoading = true; // shows spinner
this.presetSearchResults = []; // removes old results
this.selectedPresetImports = []; // removes old user sections from results
// Need the DOM to update here while waiting for promise to complete
// otherwise there is no "loading spinner" feedback to the user.
const results = await new Promise(resolve => {
let resultSet = [];
for (var x = 0; x < 10000; x++) {
console.log(x);
}
let searchResults = [];
// do search stuff
resolve(searchResults);
});
// stuff after promise
}
事实是,promise 之后的内容可以正常工作。它在执行之前等待解决方案,并按应有的方式接收正确的搜索结果数据。
问题是 DOM 在发送 promise 时没有更新,所以 UI 只是坐在那里。
有人知道我做错了什么吗?
尝试 $nextTick()
:
Vue 2.1.0+:
const results = await this.$nextTick().then(() => {
let resultSet = []
for (var x = 0; x < 10000; x++) {
console.log(x)
}
let searchResults = []
// do search stuff
return searchResults
});
任何 Vue:
const results = await new Promise(resolve => {
this.$nextTick(() => {
let resultSet = []
for (var x = 0; x < 10000; x++) {
console.log(x)
}
let searchResults = []
// do search stuff
resolve(searchResults)
})
})
Vue 将查找数据更改并将它们收集到一个数组中,以判断 DOM 之后是否需要重新渲染。这意味着 Vue 中的一切都是事件(数据)驱动的。您的函数只定义了没有数据绑定到 V-DOM 的行为。因此 Vue 引擎将不执行任何操作,因为它们的依赖数据集中没有任何更改。
我看到您的 Promise 函数将解析对变量的响应 "searchResults"。如果您的 DOM 使用该变量,Vue 引擎将在 Promise 完成后收集更改。您可以在 "data()" 中放置一个 属性 并将其绑定到 DOM.
例如:
<span v-for="(res, key) in searchResults" :key="key">
{{ res.name }}
</span>
...
<script>
export default {
...
data () {
return { searchResults: [] }
},
...
}
</script>
所以当我说 "I'm not super versed in JS promises though I generally know enough to be dangerous.".
时,我好像已经说完了我很感激有人尝试帮助我解决这个问题,但事实证明,做出承诺并不会本质上使它成为异步的。这是我的错误。问题不在于 Vue 没有更新 DOM,问题在于 promise 代码正在同步执行并阻塞 - 因此因为执行实际上从未停止等待,Vue 没有更新 [=21= 的权限].
一旦我将我的承诺代码包装在 setTimout(() => { /* all code here then: */ resolve(searchResults); }, 200);
中,一切都开始工作了。我想设置的超时允许执行停止足够长的时间让 vue 根据我之前的数据更改来更改 dom。该脚本在运行时在技术上仍然会阻止 UI,但至少我的加载程序在此过程中正在旋转,这足以满足我在这里所做的事情。
参见: