谈谈对vue中nextTick的理解

谈谈对nextTick的理解   在下次DOM更新循环结束之后执行回调 文件位置 core/utils/next-tick 异步更新原理   data属性对应一个Dep   Dep在数据访问get的时候触发Dep.depend搜集watcher   Dep在更改数据的时候set触发Dep.notify便利触发watcher更新(此处vue会调用nextTick,所以dom更新是异步的) Vue并不会立即触发watcher跟新dom(算是性能优化)。而是把具体的方法传给nextTick的callback数组中传给nextTick调用,nextTick中包含watcher等更新dom方法以及用户调用nextTick的回调函数 nextTick触发timeFunc(适配浏览器promise => MutationObserve => setImmediate => setTimeout)等异步队列,继而触发flushCallbacks循环执行callback  
 1 const callbacks = []  // 回调队列
 2 let pending = false   // 异步锁
 3 function flushCallbacks () {
 4   pending = false    // 开锁
 5   const copies = callbacks.slice(0)  // 复制一份回调数组
 6   callbacks.length = 0                   // 清空原callback数组
 7   for (let i = 0; i < copies.length; i++) {
 8     copies[i]()
 9   }
10 }
11 nextTick (cb?: Function, ctx?: Object) {
12   let _resolve
13   callbacks.push(() => {  // callback数组添加回调函数
14     if (cb) {
15       try {
16         cb.call(ctx)
17       } catch (e) {
18         handleError(e, ctx, 'nextTick')
19       }
20     } else if (_resolve) {
21       _resolve(ctx)
22     }
23   })
24   if (!pending) {     //  判断是否需要添加任务队列
25     pending = true  // 关锁
26     timerFunc()       // timeFunc为兼容浏览器的任务队列方法法promise,setTiemout等,回调执行flushCallbacks 
27   }
28   // $flow-disable-line
29   if (!cb && typeof Promise !== 'undefined') {
30     return new Promise(resolve => {
31       _resolve = resolve
32     })
33   }
34 }
next为什么定义pending锁   添加一个回调函数就关闭锁,此时处于执行完同步代码就执行异步代码的情况,这个变量作用是只开启一个异步任务,仍然可以继续添加回调函数,限制不开启多个异步更新队列

next为什么复制一份callback数组,回调函数队列

  防止nextTick套用nextTick的情况,如果不做特殊处理会出现nextTick里面的nextTick提前进入任务队列,   相当于下一个班车的乘客提前上了上一个班车(例子生动形象) 实现简易版的nexttick
 1 let pendding = false;
 2 let callback = []
 3 function flushCallback() {
 4   let copies = callback.slice(0)  // 复制一份callback
 5   callback.length = 0             // 清空callback
 6   for(var i = 0; i < copies.length; i++) {
 7     copies[i]()
 8   }
 9 }
10 function nextTick(cb) {
11   callback.push(cb)
12   if (!pendding) {   // 判断锁是否开着
13     pendding = true; // 关锁
14     setTimeout(flushCallback, 0)  // 添加一个异步任务
15   }
16 }

 

上一篇:npm版本兼容导致的npm ERR! ERESOLVE unable to resolve dependency tree


下一篇:path.join()和path.resolve()的区别