JavaScript的运行机制
主线程 和 任务队列
任务队列主要有两大类:macrotask 宏任务. 和 microtask 微任务
Macrotask: setTimeout 设置超时. MessageChannel 消息队列 . postMessage 发送信息. setImmediate 立即设置
Microtask: MutationObsever 变异 . Promise.then
事件轮询
Vue.js在修改数据的时候,不会立马修改数据,而是要等同一事件轮询的数据都更新完之后,再统一进行视图更新
//改变数据
vm.message = 'changed'
//想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
console.log(vm.$el.textContent) // 并不会得到'changed'
//这样可以,nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
console.log(vm.$el.textContent) //可以得到'changed'
})
模拟nextTick
nextTick在官网当中的定义:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
以下用setTimeout来模拟nextTick,先定义一个callbacks来存储nextTick,在下一个tick处理回调函数之前,所有的cb都会存储到这个callbacks数组当中。pending是一个标记位,代表等待的状态。接着setTimeout 会在 task 中创建一个事件 flushCallbacks ,flushCallbacks 则会在执行时将 callbacks 中的所有 cb 依次执行。
// 存储nextTick
let callbacks = [];
let pending = false;
function nextTick (cb) {
callbacks.push(cb);
if (!pending) {
// 代表等待状态的标志位
pending = true;
setTimeout(flushCallbacks, 0);
}
}
function flushCallbacks () {
pending = false;
const copies = callbacks.slice(0);
callbacks.length = 0;
for (let i = 0; i < copies.length; i++) {
copies[i]();
}
}
用途
应用场景:需要在视图更新之后,基于新的视图进行操作
<div id="app"> <input ref="input" v-show="inputShow"> <button @click="show">show</button> </div>
new Vue({
el: "#app",
data() {
return {
inputShow: false
}
},
methods: {
show() {
this.inputShow = true
this.$nextTick(() => {
this.$refs.input.focus()
})
}
}
})
参考文章:https://blog.csdn.net/sinat_17775997/article/details/82183435