Vue3函数执行期间DOM未实时更新问题及解决过程
Vue DOM更新阻塞问题排查与解决
我编写了一个切换状态变量的函数作为实际逻辑的占位实现,遇到的问题是Vue在函数执行完成前不会更新DOM,尝试使用nextTick也无效。
模板代码
<div> <q-icon v-if="status === 'DONE'" name="mdi-check-circle" color="green" size="2em"/> <q-icon v-if="status === 'PENDING'" name="mdi-checkbox-blank-circle-outline" color="orange-8" size="2em"/> <q-icon v-if="status === 'FAILED'" name="mdi-alert-circle" color="red-8" class="q-pr-sm" size="2em"/> <q-spinner-pie v-if="status === 'PROCESSING'" color="primary" size="2em" class="q-pr-sm" /> <span class="text-italic text-caption" >( {{ curTotal }} / {{ itemTotal }} )</span> </div>
初始实现与问题
最初的函数实现中使用了自定义的sleep函数模拟耗时操作:
processImages(){ this.status = 'PROCESSING' for ( let i = 0; i < this.itemTotal; i++){ this.sleep(1000) this.curTotal += 1 } } sleep(miliseconds) { var currentTime = new Date().getTime(); while (currentTime + miliseconds >= new Date().getTime()) { } }
执行后发现status切换为PROCESSING的状态图标和curTotal的更新都不会实时展示,直到整个函数执行完成后才一次性更新DOM。
问题根源
上述sleep函数通过同步while循环阻塞主线程,JavaScript是单线程模型,主线程被阻塞时,Vue的异步DOM更新队列根本没有机会执行,导致所有DOM更新被推迟到函数执行完毕后才进行,nextTick也无法解决这个问题——因为它只是等待下一次DOM更新周期,但主线程被占着根本轮不到更新周期执行。
修正后的实现
将同步阻塞的sleep替换为异步的API调用(使用async/await)后,DOM更新恢复正常:
async processImages(){ this.rows[0].status = 'PROCESSING' for ( let i = 0; i < this.itemTotal; i++){ const { data } = await $fetch('/api/scrape', { method: 'GET', }) this.rows[0].curTotal += 1 } this.rows[0].created = true }
await会在API请求期间释放主线程,让Vue的DOM更新队列有机会执行,因此status和curTotal的变化能实时反映到页面上。
内容的提问来源于stack exchange,提问作者Tom T
相关产品推荐
相关产品推荐

