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)
    

    最后我画出了队列图

    队列执行图

    相关文章

      网友评论

      • 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