侧边栏壁纸
  • 累计撰写 14 篇文章
  • 累计创建 15 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

Vue2 nextTick 解析

xrdev
2022-09-08 / 0 评论 / 0 点赞 / 67 阅读 / 470 字 / 正在检测是否收录...

Vue2 nextTick 解析

会执行函数生成一个闭包函数

export const nextTick = (function () {...})()

 // 函数体
const callbacks = [] // 所有的$nextTick(fn) ,这里的fn 都会 push 到这个数组中
let pending = false // 加锁
let timerFunc  // 异步处理方法

// 处理 callbask 里面所有回调方法
function nextTickHandler () {
    pending = false // 解锁
    const copies = callbacks.slice(0) // 转换数组
    callbacks.length = 0 // 
    for (let i = 0; i < copies.length; i++) {
      copies[i]() // 执行回调函数
    }
}

// 判断浏览器是否原生支持Promise (使用微任务Jobs 处理比宏任务Task,可以更早的时机执行 )
if (typeof Promise !== 'undefined' && isNative(Promise)) { 
  var p = Promise.resolve() // 生成一个空的Promise 实例 
  // 封装一个函数
  timerFunc = () => {
    // 处理nextTick 接受的所有回调函数
    p.then(nextTickHandler)
  }
} 
 // 判断浏览器环境是否支持 MutationObserver (H5新特性)
else if (typeof MutationObserver !== 'undefined' && (
    isNative(MutationObserver) ||
    MutationObserver.toString() === '[object MutationObserverConstructor]'
  )) {
  var counter = 1 
  var observer = new MutationObserver(nextTickHandler)  // 创建监听对象MutationObserver
  var textNode = document.createTextNode(String(counter))  // 创建一个文本dom节点
  observer.observe(textNode, { // 监听这个文本 节点
    characterData: true 
  })
  // 封装一个函数
  timerFunc = () => {
    counter = (counter + 1) % 2 
    textNode.data = String(counter) // 通过修改文本节点的值,从而触发MutationObserver 监听的回调 nextTickHandler
  }
} 
// 以上都不支持的话, 就使用宏任务(Task) 定时器实现
else {
    // fallback to setTimeout
    /* istanbul ignore next */
    timerFunc = setTimeout 
  }
  // 主要的方法 ;闭包函数返回的函数, this.$nextTick 调用的就是这里的方法
  return function queueNextTick (cb: Function, ctx?: Object) {
    // cb: nextTick 回调函数
    // ctx: vue的实例
    const func = ctx // 如果有ctx, 就call指向当前回调函数的this 为 ctx
      ? function () { cb.call(ctx) }
      : cb
    // 将回调函数push 到 callbacks 中
    callbacks.push(func)
    // 通过pending判断锁, 是否执行完所有的回调了, 或者有可能是第一次进入
    if (!pending) {
      pending = true // 加锁
      timerFunc(nextTickHandler, 0) // 通常写timerFunc() 就行, 这是为了兼容setTimeout
    }
  }


0

评论区