vue->$nextTick
引用官方的话:为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback)
- ex1
<div><button @click="add">add</button><div ref="tagName">{{name}}</div>
</div>
data () {return {name: merlo}
}
methods: {add() {this.name = 'iron man'console.log(this.$ref['tagName'].innerHTML) // 仍然是merlothis.$nextTick((v) => {console.log(this.$ref['tagName'].innerHTML) // 已经变成iron man})}
}
- ex2
<div><button @click="add">add</button><div ref="tagName" :style="css">{{info}}</div>
</div>
data() {return {css: { height: '666px'}}
}
methods: {add() {this.css = { height: '666666px' }console.log(this.$ref['tagName'].offsetHeight) // 依然666pxthis.$nextTick((v) => {console.log(this.$ref['tagName'].offsetHeight) // 变成666666px})}
}
相关原理
在 Vue 2.4 之前都是使用的 microtasks,但是 microtasks 的优先级过高,在某 些情况下可能会出现比事件冒泡更快的情况,但如果都使用 macrotasks 又可能会出现 渲染的性能问题。所以在新版本中,会默认使用 microtasks,但在特殊情况下会使用 macrotasks,比如 v-on。
macrotasks: microtasks的作用是用来调度应在当前执行的脚本执行结束后立即执行的任务。 例如响应事件、或者异步操作,以避免付出额外的一个task的费用。
- I/O
- setTimeout
- setInterval
- setImmediate
- requestAnimationFrame
- UI rendering
microtasks: 就是常说的任务队列task queue
,作用是为了让浏览器能够从内部获取javascript / dom的内容并确保执行栈能够顺序进行。
- process.nextTick
- Promises
- Object.observe
- MutationObserver
ex:
setTimeout(function(){console.log(1)},0);new Promise(function(resolve){console.log(2)for( var i=100000 ; i>0 ; i-- ){i==1 && resolve()}console.log(3)}).then(function(){console.log(4)});console.log(5);// 以上打印结果 2,3,5,4,1
tip:
在Microsoft Edge, Firefox 40, iOS Safari 以及 desktop Safari 8.0.8 中setTimeout会先于Promise
参考资料: - macrotask within an event loop context - 知乎-Promise的队列与setTimeout的队列有何关联? - 通过microtasks和macrotasks看JavaScript异步任务执行顺序 - 阮一峰-JavaScript 运行机制详解:再谈Event Loop