摘要:頁面這個實例,按理就需要解析兩次,但是有緩存之后就不會理清思路也就是說,其實內(nèi)核就是不過是經(jīng)過了兩波包裝的第一波包裝在中的內(nèi)部函數(shù)中內(nèi)部函數(shù)的作用是合并公共和自定義,但是相關(guān)代碼已經(jīng)省略,另一個就是執(zhí)行第二波包裝在中,目的是進(jìn)行緩存
寫文章不容易,點個贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】
如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧
【Vue原理】Compile - 源碼版 之 從新建實例到 compile結(jié)束的主要流程
Compile 的內(nèi)容十分之多,今天先來個熱身,先不研究 compile 內(nèi)部編譯細(xì)節(jié),而是記錄一下
從新建實例開始,到結(jié)束 compile ,其中的大致外部流程,不涉及 compile 的內(nèi)部流程
或者說,我們要研究 compile 這個函數(shù)是怎么生成的
注意,如果你沒有準(zhǔn)備好,請不要閱讀這篇文章
注意哦,會很繞,別暈了
好的,正文開始
首先,當(dāng)我們通過 Vue 新建一個實例的時候會調(diào)用Vue
所以從 Vue 函數(shù)入手
function Vue(){ // ..... vm.$mount(vm.$options.el); }
然后內(nèi)部的其他處理都可以忽視,直接定位到 vm.$mount,就是從這里開始去編譯的
繼續(xù)去查找這個函數(shù)
Vue.prototype.$mount = function(el) { var options = this.$options; if (!options.render) { var tpl= options.template; // 獲取模板字符串 if (tpl) { // 根據(jù)傳入的選擇器找到元素,然后拿到該元素內(nèi)的模板 // 本來有很多種獲取方式,但是為了簡單,我們簡化為一種,知道意思就可以了 tpl = document.querySelector(tpl).innerHTML; } if (tpl) { // 生成 render 函數(shù)保存 var ref = compileToFunctions(tpl, {},this); // 每一個組件,都有自己的 render options.render = ref.render options.staticRenderFns =ref.staticRenderFns; } } // 執(zhí)行上面生成的 render,生成DOM,掛載DOM,這里忽略不討論 return mount.call(this, el) };
compile 的主要作用就是,根據(jù) template 模板,生成 render 函數(shù)
那么到這里,整個流程就走完了,因為 render 已經(jīng)在這里生成了
我們觀察到
在上面這個函數(shù)中,主要就做了三件事
1 獲取 template 模板根據(jù)你傳入的參數(shù),來各種獲取 template 模板
這里應(yīng)該都看得懂了,根據(jù)DOM,或者根據(jù)選擇器
2 生成 render通過 compileToFunctions ,傳入 template
就可以生成 render 和 staticRenderFns
看著是挺簡單哦,就一個 compileToFunctions,但是我告訴你,這個函數(shù)的誕生可不是這么容易的,兜兜轉(zhuǎn)轉(zhuǎn),十分曲折,相當(dāng)?shù)们蹚?fù)雜,沒錯,這就是我們下面研究的重點
但是這流程其實好像也沒有什么幫助?但是如果你閱讀源碼的話,或許可以對你理清源碼有些許幫助吧
再一次佩服 尤大的腦回路
3 保存 render保存在 vm.$options 上,用于在后面調(diào)用
下面就來說 compileToFunctions 的誕生史
注意,很繞很繞,做好心理準(zhǔn)備
首先我定位到 compileToFunctions,看到下面這段代碼
var ref$1 = createCompiler(); // compileToFunctions 會返回 render 函數(shù) 以及 staticRenderFns var compileToFunctions = ref$1.compileToFunctions;
于是我知道
compileToFunctions 是 createCompiler 執(zhí)行返回的!!
那么繼續(xù)定位 createCompiler
createCompilervar 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 } } );
臥槽,又來一個函數(shù),別暈啊兄弟
不過,注意注意,這里是重點,非常重
首先明確兩點
1、createCompiler 是 createCompilerCreator 生成的
2、給 createCompilerCreator 傳了一個函數(shù) baseCompile
baseCompile這個 baseCompile 就是 生成 render 的大佬
看到里面包含了 渲染三巨頭,【parse,optimize,generate】
但是今天不是講這個的,這三個東西,每個內(nèi)容都十分巨大
這里先跳過,反正 baseCompile 很重要,會在后面被調(diào)用到,得先記著
然后,沒錯,我們又遇到了一個 函數(shù) createCompilerCreator ,定位它!
createCompilerCreatorfunction createCompilerCreator(baseCompile) { return function () { // 作用是合并選項,并且調(diào)用 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 // 得到一個函數(shù),這個函數(shù)是 把 render 字符串包在 函數(shù) 中 compileToFunctions: createCompileToFunctionFn(compile) } } }
這個函數(shù)執(zhí)行過后,會返回一個函數(shù)
很明顯,返回的函數(shù)就 直接賦值 給了上面講的的 createCompiler
我們看下這個返回給 createCompiler 的函數(shù)里面都干了什么?
生成一個函數(shù) compile內(nèi)部存在一個函數(shù) compile,這個函數(shù)主要作用是
調(diào)用 baseCompile,把 baseCompile 執(zhí)行結(jié)果 return 出去
baseCompile 之前我們強(qiáng)調(diào)過的,就是那個生成 render 的大佬
忘記的,可以回頭看看,執(zhí)行完畢會返回
{ render,staticRenderFns }
返回 compileToFunctions 和 compile其實 返回的這兩個函數(shù)的作用大致都是一樣的
都是為了執(zhí)行上面那個 內(nèi)部 compile
但是為什么分出一個 compileToFunctions 呢?還記得開篇我們的 compileToFunctions 嗎
就是那個在 vm.$mount 里我們要探索的東西啊
就是他這個吊毛,生成的 render 和 staticRenderFns
再看看那個 內(nèi)部 compile,可以看到他執(zhí)行完就是返回
{ render, staticRenderFns }
你看,內(nèi)部 compile 就是 【vm.$mount 執(zhí)行的 compileToFunctions】 啊
為什么 compileToFunctions 沒有直接賦值為 compile 呢!!
因為要做模板緩存??!可以看到,沒有直接讓 compileToFunctions = 內(nèi)部compile
而是把 內(nèi)部 compile 傳給了 createCompileToFunctionFn
沒錯 createCompileToFunctionFn 就是做緩存的
為了避免每個實例都被編譯很多次,所以做緩存,編譯一次之后就直接取緩存
createCompileToFunctionFn來看看內(nèi)部的源碼,緩存的代碼已經(jīng)標(biāo)紅
function createCompileToFunctionFn(compile) { // 作為緩存,防止每次都重新編譯 // template 字符串 為 key , 值是 render 和 staticRenderFns var cache = Object.create(null); return function compileToFunctions(template, options, vm) { var key = template; // 有緩存的時候直接取出緩存中的結(jié)果即可 if (cache[key]) return cache[key] // compile 是 createCompileCreator 傳入的compile var compiled = compile(template, options); var res = { // compiled.render 是字符串,需要轉(zhuǎn)成函數(shù) render : new Function(compiled.render) staticRenderFns : compiled.staticRenderFns.map(function(code) { return new Function(code, fnGenErrors) }); }; return (cache[key] = res) } }
額外:render 字符串變成可執(zhí)行函數(shù)
var res = { render: new Function(compiled.render) , staticRenderFns: compiled.staticRenderFns.map(function(code) { return new Function(code, fnGenErrors) }); };
這段代碼把 render 字符串可執(zhí)行函數(shù),因為render生成的形態(tài)是一個字符串,如果后期要調(diào)用運(yùn)行,比如轉(zhuǎn)成函數(shù)
所以這里使用了 new Function() 轉(zhuǎn)化成函數(shù)
同理,staticRenderFns 也一樣,只不過他是數(shù)組,需要遍歷,逐個轉(zhuǎn)化成函數(shù)
他的緩存是怎么做的使用一個 cache 閉包變量
template 為 key
生成的 render 作為 value
當(dāng)實例第一次渲染解析,就會被存到 cache 中
當(dāng)實例第二次渲染解析,那么就會從 cache 中直接獲取
什么時候?qū)嵗龝馕龅诙危?/p>
比如 頁面A到頁面B,頁面B又轉(zhuǎn)到頁面A。
頁面A 這個實例,按理就需要解析兩次,但是有緩存之后就不會
理清思路也就是說,compileToFunctions 其實內(nèi)核就是 baseCompile!
不過 compileToFunctions 是經(jīng)過了 兩波包裝的 baseCompile
第一波包裝在 createCompilerCreator 中的 內(nèi)部 compile 函數(shù)中
內(nèi)部函數(shù)的作用是合并公共options和 自定義options ,但是相關(guān)代碼已經(jīng)省略,
另一個就是執(zhí)行 baseCompile
第二波包裝在 createCompileToFunctions 中,目的是進(jìn)行 緩存
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106565.html
摘要:當(dāng)字符串開頭是時,可以匹配匹配尾標(biāo)簽。從結(jié)尾,找到所在位置批量閉合。 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】Compile - 源碼版 之 標(biāo)簽解析...
寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】Compile - 源碼版 之 Parse 主要流程 本文難度較繁瑣,需要耐心觀看,如果你對 compile 源碼暫時...
摘要:一旦我們檢測到這些子樹,我們可以把它們變成常數(shù),這樣我們就不需要了在每次重新渲染時為它們創(chuàng)建新的節(jié)點在修補(bǔ)過程中完全跳過它們。否則,吊裝費(fèi)用將會增加好處大于好處,最好總是保持新鮮。 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,...
摘要:還原的難度就在于變成模板了,因為其他的什么等是原封不動的哈哈,可是直接照抄最后鑒于本人能力有限,難免會有疏漏錯誤的地方,請大家多多包涵,如果有任何描述不當(dāng)?shù)牡胤?,歡迎后臺聯(lián)系本人,有重謝 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理白話版終于到了要講白話的時候了 寫文章不容易,點個贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究...
閱讀 915·2019-08-30 15:54
閱讀 1479·2019-08-30 15:54
閱讀 2406·2019-08-29 16:25
閱讀 1300·2019-08-29 15:24
閱讀 755·2019-08-29 12:11
閱讀 2513·2019-08-26 10:43
閱讀 1236·2019-08-26 10:40
閱讀 474·2019-08-23 16:24