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