Vue2.0中的异步队列

作者: cpu_driver | 来源:发表于2017-03-21 18:53 被阅读233次

在vue的体系中,数据的双向绑定主要通过<code>Object.defineProperty</code>进行数据从模型到视图的流动及通过DOM事件进行数据从视图到模型的流动。这些都比较容易理解,但是如果频繁的更改模型的话,就会造成频繁的更新View,会造成频繁的dom操作,这是比较耗时的,因此需要进行优化,Vue2.0是通过批处理进行优化的,而异步执行队列,是批处理中一个很重要的一个环节。

在vue.js(Vue.js v2.1.10)416-490行,描述了这一神奇的异步执行队列。下面我们将进行相关的代码分析。

  • 1.函数整体
var nextTick =(function(){
  return function queueNextTick (cb, ctx) {}
})()

我们可以看到整体来说,这是一个由立即执行函数构成的,返回值是函数的一个函数,我们可以使用下面的测试代码

var nextTick =(function(){
return function queueNextTick (cb, ctx) {
  console.log(cb);
}
})();
nextTick("this is test1")
  • 2.函数内容
var nextTick = (function () {
    var callbacks = [];
    var pending = false;
    var timerFunc;

    function nextTickHandler () {
    }
  if (typeof Promise !== 'undefined' && isNative(Promise)) {
    var p = Promise.resolve();
    var logError = function (err) { console.error(err); };
    timerFunc = function () {
      p.then(nextTickHandler).catch(logError);
      if (isIOS) { setTimeout(noop); }
    };
  } else if (typeof MutationObserver !== 'undefined' && (
    isNative(MutationObserver) ||
    MutationObserver.toString() === '[object MutationObserverConstructor]'
  )) {
    var counter = 1;
    var observer = new MutationObserver(nextTickHandler);
    var textNode = document.createTextNode(String(counter));
    observer.observe(textNode, {
      characterData: true
    });
    timerFunc = function () {
  }
  return function queueNextTick (cb, ctx) {
  }
})();

我们看到在函数内部,有三个函数,nextTickHandler,timerFunc,以及queueNextTick 。
其中

if(typeof Promise !== 'undefined' && isNative(Promise)){
}
else if(typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  MutationObserver.toString() === '[object MutationObserverConstructor]'){
}else{
}

是用来判断当前执行环境,给timerFunc 选择一个合适的执行条件。如果是支持Promise的环境中,timerFunc 中则用<code>p.then(nextTickHandler)</code>和 <code>setTimeout(nextTickHandler, 0);</code>执行回调;如果是MutationObserver环境则通过修改文本节点的值的变化触发调用的的。关于为什么优先使用Promise,知乎里也在讨论这件事,点这里看详情。

  • 3.函数的返回函数
function queueNextTick (cb, ctx) {
    var _resolve;
    callbacks.push(function () {
      if (cb) { cb.call(ctx); }
      if (_resolve) { 
          console.log(0);
           _resolve(ctx); }
    });
    if (!pending) {
      pending = true;
      timerFunc();
    }
    if (!cb && typeof Promise !== 'undefined') {
      return new Promise(function (resolve) {
          console.log("now")
        _resolve = resolve;
      })
    }
  }

当我们使用<code>nextTick(function Test(){console.log("1" +this.isIOS);},this)</code>时,我们可以发现 Test封装后被放进了回调队列callbacks中,

if (cb) { cb.call(ctx); }
if (_resolve) { 
       console.log(0);
        _resolve(ctx); }

注意这里的_resolve,他是在

if (!cb && typeof Promise !== 'undefined') {
   return new Promise(function (resolve) {
     _resolve = resolve;
   })
 }

里面进行了赋值,因为promise注册函数是立即执行的,因此在返回前给当前的域中的_resolve赋了值。当进行回调时,便可以使用_resolve的值。我们可以使用执行空函数进行测试:

console.log(nextTick();)//打印是Promise的相关内容 
  • 4.nextTickHandler队列回调控制函数
function nextTickHandler () {
    pending = false;
    //对callbacks进行深复制
    var copies = callbacks.slice(0);
    callbacks.length = 0;
    for (var i = 0; i < copies.length; i++) {
        if(i==0){
            copies[i]();
        }
      copies[i]();
    }
  }

此函数便是在触发时把回调队列中函数依次调用,特别注意 pending=flase这句话用来把执行回调过程中新加进回调数组的计入下一个tick,另外需要注意<code> var copies =callbacks.slice(0); callbacks.length = 0;
</code>这句话,用的很好,首先对回掉数组进行深复制,然后把callbacks置空。之所以不用callbacks=[],是因为设置length=0可以不改变原有对象的地址。

  • 5.如何实现队列的功能
    我们使用测试代码:
nextTick().then(()=>{
  console.log("last");
})
var ss={
    isIOS:"sss"
}
nextTick(function(){
    console.log("1" +this.isIOS);
},ss)

最后我画出了队列图

队列执行图

相关文章

  • Vue2.0中的异步队列

    在vue的体系中,数据的双向绑定主要通过 Object.defineProperty 进行数据从模型到视图的流动及...

  • GCD

    1、同步串行队列 2、同步并行队列 3、异步串行队列 4、异步并行队列 5、死锁 主线程中创建同步串行队列 主线程...

  • GCD基础总结一

    上代码~ 同步串行队列 同步并行队列 异步串行队列 异步并行队列 主队列同步 会卡住 主队列异步

  • AskMe项目 异步队列

    异步队列简单介绍 队列实现异步可以用单向队列,任务放到队列中,先进先出,或者使用优先队列,按照优先级来选择谁先执行...

  • GCD的几种创建方式及基本使用

    同步函数 同步函数+主队列 同步函数+串行队列 同步函数+并发队列 异步函数 异步函数+主队列 异步函数+串行队列...

  • nextTick、setImmediate、promise.re

    执行队列(同步) 任务队列(异步事件) 每当异步任务完成后会在任务队列中添加一个关联事件,待执行队列任务执行完成...

  • GCD队列、同步异步

    GCD队列、同步异步 GCD队列、同步异步

  • CGD相关知识

    GCD队列总体分为同步队列和异步队列两种,添加到同步队列中的任务,根据添加的顺序挨个执行,添加到异步队列里面的任务...

  • dispatch_apply循环遍历

    dispatch_apply可以 在多个线程中同时(异步)遍历多个数字。无论是在串行队列,还是异步队列中,disp...

  • 多线程GCD笔记

    同步函数 + 主队列 异步函数 + 主队列 同步函数 + 串行队列 异步函数 + 串行队列 同步函数 + 并发队列...

网友评论

  • 5925d5123ff6:cpu_driver 你好,我把此文章放到了 linkedinfo.co ,我的一个业余小项目。如您觉得不妥,请随时联系我将之撤下。

    linkedinfo.co 是一个集合了各类优秀技术文章的站点,不展现全文,所有条目都附上作者与原文链接,读者最终都会进入到作者原文的站点。做 linkedinfo 的初衷是想方便自己且方便其他想学习的朋友,能更方便地找到自己感兴趣的技术文章。同时这也是一个我自己练习的过程,比如将正在学习的 Semantic Web 技术应用到 linkedinfo 来更好地连接不同的知识。

    各位感兴趣的朋友可以去 https://linkedinfo.co 看看,非常希望能得到你们的意见与建议 (可在about 页面留言 https://linkedinfo.co/about )。

本文标题:Vue2.0中的异步队列

本文链接:https://www.haomeiwen.com/subject/wvninttx.html