Vue中的nextTick原理解析

nextTick的使用場景

nextTick是全局vue的一個函數,在vue系統中,用於處理dom更新的操作。vue裏面有一個watcher,用於觀察數據的變化,然後更新dom,vue裏面並不是每次數據改變都會觸發更新dom,而是將這些操作都緩存在一個隊列,在一個事件循環結束之後,刷新隊列,統一執行dom更新操作。
通常情況下,我們不需要關心這個問題,而如果想在DOM狀態更新後做點什麼,則需要用到nextTick。在vue生命週期的created()鉤子函數進行的DOM操作要放在Vue.nextTick()的回調函數中,因爲created()鉤子函數執行的時候DOM並未進行任何渲染,而此時進行DOM操作是徒勞的,所以此處一定要將DOM操作的JS代碼放進Vue.nextTick()的回調函數中。而與之對應的mounted鉤子函數,該鉤子函數執行時所有的DOM掛載和渲染都已完成,此時該鉤子函數進行任何DOM操作都不會有個問題。
nextTick源碼分析

var nextTick=(function () {
    //存儲需要觸發的回調函數
    var callbacks=[];
    //是否正在等待的標誌(false:允許觸發在下次事件循環觸發callbacks中的回調,
    // true: 已經觸發過,需要等到下次事件循環)
    var pending=false;
    //設置在下次事件循環觸發callbacks的觸發函數
    var timerFunc;
    //處理callbacks的函數
    function nextTickHandler() {
        // 可以觸發timeFunc
        pending=false;
        //複製callback
        var copies=callbacks.slice(0);
        //清除callback
        callbacks.length=0;
        for(var i=0;i<copies.length;i++){
            //觸發callback的回調函數
            copies[i]();
        }
    }
    //如果支持promise,使用promise實現
    if(typeof Promise !=='undefined' && isNative(promise)){
        var p=Promise.resolve();
        var logError=function (err) {
            console.error(err);
        };
        timerFunc=function () {
            p.then(nextTickHandler).catch(logError);
            //iOS的webview下,需要強制刷新隊列,執行上面的回調函數
            if(isIOS) {setTimeout(noop);}
        };
    //    如果Promise不支持,但支持MutationObserver
    //    H5新特性,異步,當dom變動是觸發,注意是所有的dom都改變結束後觸發
    } 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 () {
                counter=(counter+1)%2;
                textNode.data=String(counter);
            };
    } else {
        //上面兩種都不支持,用setTimeout
        timerFunc=function () {
            setTimeout(nextTickHandler,0);
        };
    }
    //nextTick接收的函數,參數1:回調函數 參數2:回調函數的執行上下文
    return function queueNextTick(cb,ctx) {
        //用於接收觸發Promise.then中回調的函數
        //向回調函數中pushcallback
        var _resolve;
        callbacks.push(function () {
            //如果有回調函數,執行回調函數
            if(cb) {cb.call(ctx);}
            //觸發Promise的then回調
            if(_resolve) {_resolve(ctx);}
        });
        //是否執行刷新callback隊列
        if(!pending){
            pending=true;
            timerFunc();
        }
        //如果沒有傳遞迴調函數,並且當前瀏覽器支持promise,使用promise實現
        if(!cb && typeof  Promise !=='undefined'){
            return new Promise(function (resolve) {
                _resolve=resolve;
            })
        }
    }
})

詳情內容點我

發佈了95 篇原創文章 · 獲贊 22 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章