成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Vue原理】Compile - 源碼版 之 從新建實例到 compile結束的主要流程

CODING / 1237人閱讀

摘要:頁面這個實例,按理就需要解析兩次,但是有緩存之后就不會理清思路也就是說,其實內核就是不過是經過了兩波包裝的第一波包裝在中的內部函數中內部函數的作用是合并公共和自定義,但是相關代碼已經省略,另一個就是執(zhí)行第二波包裝在中,目的是進行緩存

寫文章不容易,點個贊唄兄弟  


專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧
研究基于 Vue版本 【2.5.17】

如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧

【Vue原理】Compile - 源碼版 之 從新建實例到 compile結束的主要流程

Compile 的內容十分之多,今天先來個熱身,先不研究 compile 內部編譯細節(jié),而是記錄一下

從新建實例開始,到結束 compile ,其中的大致外部流程,不涉及 compile 的內部流程

或者說,我們要研究 compile 這個函數是怎么生成的

注意,如果你沒有準備好,請不要閱讀這篇文章

注意哦,會很繞,別暈了

好的,正文開始

首先,當我們通過 Vue 新建一個實例的時候會調用Vue

所以從 Vue 函數入手

function Vue(){    

    // .....

    vm.$mount(vm.$options.el);
}

然后內部的其他處理都可以忽視,直接定位到 vm.$mount,就是從這里開始去編譯的

繼續(xù)去查找這個函數

Vue.prototype.$mount = function(el) {    



    var options = this.$options;

   

    if (!options.render) {  

     

        var tpl= options.template;  

   

        // 獲取模板字符串
        if (tpl) {    

                // 根據傳入的選擇器找到元素,然后拿到該元素內的模板

                //  本來有很多種獲取方式,但是為了簡單,我們簡化為一種,知道意思就可以了

            tpl = document.querySelector(tpl).innerHTML;
        }    

     

        if (tpl) {  

            // 生成 render 函數保存

            var ref = compileToFunctions(tpl, {},this);  

          

            // 每一個組件,都有自己的 render

            options.render = ref.render
            options.staticRenderFns =ref.staticRenderFns;
        }
    }      



    // 執(zhí)行上面生成的 render,生成DOM,掛載DOM,這里忽略不討論
    return mount.call(this, el)
};

compile 的主要作用就是,根據 template 模板,生成 render 函數

那么到這里,整個流程就走完了,因為 render 已經在這里生成了

我們觀察到

在上面這個函數中,主要就做了三件事

1 獲取 template 模板

根據你傳入的參數,來各種獲取 template 模板

這里應該都看得懂了,根據DOM,或者根據選擇器

2 生成 render

通過 compileToFunctions ,傳入 template

就可以生成 render 和 staticRenderFns

看著是挺簡單哦,就一個 compileToFunctions,但是我告訴你,這個函數的誕生可不是這么容易的,兜兜轉轉,十分曲折,相當得曲折復雜,沒錯,這就是我們下面研究的重點

但是這流程其實好像也沒有什么幫助?但是如果你閱讀源碼的話,或許可以對你理清源碼有些許幫助吧

再一次佩服 尤大的腦回路

3 保存 render

保存在 vm.$options 上,用于在后面調用

下面就來說 compileToFunctions 的誕生史

注意,很繞很繞,做好心理準備

首先我定位到 compileToFunctions,看到下面這段代碼

var ref$1 = createCompiler();



// compileToFunctions 會返回 render 函數 以及 staticRenderFns

var compileToFunctions = ref$1.compileToFunctions;

于是我知道

compileToFunctions 是 createCompiler 執(zhí)行返回的??!

那么繼續(xù)定位 createCompiler

createCompiler
var createCompiler = createCompilerCreator(  



    function baseCompile(template, options) {    

    

        var ast = parse(template.trim(), options);    

    

        if (options.optimize !== false) {

            optimize(ast, options);
        }    

   

        var code = generate(ast, options);  

     

        return {            

            ast: ast,            

            render: code.render,            

            staticRenderFns: code.staticRenderFns

        }
    }
);

臥槽,又來一個函數,別暈啊兄弟


不過,注意注意,這里是重點,非常重

首先明確兩點

1、createCompiler 是 createCompilerCreator 生成的

2、給 createCompilerCreator 傳了一個函數 baseCompile

baseCompile

這個 baseCompile 就是 生成 render 的大佬

看到里面包含了 渲染三巨頭,【parse,optimize,generate】

但是今天不是講這個的,這三個東西,每個內容都十分巨大

這里先跳過,反正 baseCompile 很重要,會在后面被調用到,得先記著

然后,沒錯,我們又遇到了一個 函數 createCompilerCreator ,定位它!

createCompilerCreator
function createCompilerCreator(baseCompile) {    



    return function () {

       

        // 作用是合并選項,并且調用 baseCompile
        function compile(template) {  

         

            // baseCompile 就是 上一步傳入的,這里執(zhí)行得到 {ast,render,statickRenderFn}

            var compiled = baseCompile(template);            

            return compiled

        }        

        return {          



            // compile 執(zhí)行會返回 baseCompile 返回的 字符串 render

            compile: compile,      

     

            // 為了創(chuàng)建一層 緩存閉包,并且閉包保存 compile

            // 得到一個函數,這個函數是 把 render 字符串包在 函數 中
            compileToFunctions: createCompileToFunctionFn(compile)
        }
    }
}

這個函數執(zhí)行過后,會返回一個函數

很明顯,返回的函數就 直接賦值 給了上面講的的 createCompiler

我們看下這個返回給 createCompiler 的函數里面都干了什么?

生成一個函數 compile

內部存在一個函數 compile,這個函數主要作用是

調用 baseCompile,把 baseCompile 執(zhí)行結果 return 出去

baseCompile 之前我們強調過的,就是那個生成 render 的大佬

忘記的,可以回頭看看,執(zhí)行完畢會返回

{ render,staticRenderFns }

返回 compileToFunctions 和 compile

其實 返回的這兩個函數的作用大致都是一樣的

都是為了執(zhí)行上面那個 內部 compile

但是為什么分出一個 compileToFunctions 呢?

還記得開篇我們的 compileToFunctions 嗎

就是那個在 vm.$mount 里我們要探索的東西啊

就是他這個吊毛,生成的 render 和 staticRenderFns

再看看那個 內部 compile,可以看到他執(zhí)行完就是返回

{ render, staticRenderFns }

你看,內部 compile 就是 【vm.$mount 執(zhí)行的 compileToFunctions】 啊

為什么 compileToFunctions 沒有直接賦值為 compile 呢??!

因為要做模板緩存??!

可以看到,沒有直接讓 compileToFunctions = 內部compile

而是把 內部 compile 傳給了 createCompileToFunctionFn

沒錯 createCompileToFunctionFn 就是做緩存的

為了避免每個實例都被編譯很多次,所以做緩存,編譯一次之后就直接取緩存

createCompileToFunctionFn

來看看內部的源碼,緩存的代碼已經標紅

function createCompileToFunctionFn(compile) {    



    // 作為緩存,防止每次都重新編譯

    // template 字符串 為 key , 值是 render 和 staticRenderFns
    var cache = Object.create(null);    



    return function compileToFunctions(template, options, vm) {        

        var key = template;        



        // 有緩存的時候直接取出緩存中的結果即可

        if (cache[key]) return cache[key]  

     

        // compile 是 createCompileCreator 傳入的compile

        var compiled = compile(template, options);        

        var res = {            



            // compiled.render 是字符串,需要轉成函數

            render : new Function(compiled.render)
            staticRenderFns : compiled.staticRenderFns.map(function(code) {                

                return  new Function(code, fnGenErrors)

            });
        };        



        return (cache[key] = res)

    }
}

額外:render 字符串變成可執(zhí)行函數

var res = {    

    render: new Function(compiled.render) ,    

    staticRenderFns: compiled.staticRenderFns.map(function(code) {        

        return new Function(code, fnGenErrors)

    });
};

這段代碼把 render 字符串可執(zhí)行函數,因為render生成的形態(tài)是一個字符串,如果后期要調用運行,比如轉成函數

所以這里使用了 new Function() 轉化成函數

同理,staticRenderFns 也一樣,只不過他是數組,需要遍歷,逐個轉化成函數

他的緩存是怎么做的

使用一個 cache 閉包變量

template 為 key

生成的 render 作為 value

當實例第一次渲染解析,就會被存到 cache 中

當實例第二次渲染解析,那么就會從 cache 中直接獲取

什么時候實例會解析第二次?

比如 頁面A到頁面B,頁面B又轉到頁面A。

頁面A 這個實例,按理就需要解析兩次,但是有緩存之后就不會

理清思路

也就是說,compileToFunctions 其實內核就是 baseCompile!

不過 compileToFunctions 是經過了 兩波包裝的 baseCompile

第一波包裝在 createCompilerCreator 中的 內部 compile 函數中

內部函數的作用是

合并公共options和 自定義options ,但是相關代碼已經省略,

另一個就是執(zhí)行 baseCompile

第二波包裝在 createCompileToFunctions 中,目的是進行 緩存

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/106565.html

相關文章

  • Vue原理Compile - 源碼 Parse 標簽解析

    摘要:當字符串開頭是時,可以匹配匹配尾標簽。從結尾,找到所在位置批量閉合。 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Compile - 源碼版 之 標簽解析...

    loostudy 評論0 收藏0
  • Vue原理Compile - 源碼 Parse 主要流程

    寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Compile - 源碼版 之 Parse 主要流程 本文難度較繁瑣,需要耐心觀看,如果你對 compile 源碼暫時...

    Forest10 評論0 收藏0
  • Vue原理Compile - 源碼 optimize 標記靜態(tài)節(jié)點

    摘要:一旦我們檢測到這些子樹,我們可以把它們變成常數,這樣我們就不需要了在每次重新渲染時為它們創(chuàng)建新的節(jié)點在修補過程中完全跳過它們。否則,吊裝費用將會增加好處大于好處,最好總是保持新鮮。 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,...

    Soarkey 評論0 收藏0
  • Vue原理Compile - 源碼 generate 節(jié)點拼接

    摘要:還原的難度就在于變成模板了,因為其他的什么等是原封不動的哈哈,可是直接照抄最后鑒于本人能力有限,難免會有疏漏錯誤的地方,請大家多多包涵,如果有任何描述不當的地方,歡迎后臺聯系本人,有重謝 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版...

    macg0406 評論0 收藏0
  • Vue原理Compile - 白話

    摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理白話版終于到了要講白話的時候了 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究...

    dingding199389 評論0 收藏0

發(fā)表評論

0條評論

CODING

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<