欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue編譯器源碼分析compileToFunctions作用詳解

 更新時間:2022年07月13日 17:44:01   作者:李李  
這篇文章主要為大家介紹了Vue編譯器源碼分析compileToFunctions作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

接上篇Vue編譯器源碼分析文章我們來分析:compileToFunctions的作用。

經(jīng)過前面的講解,我們已經(jīng)知道了 compileToFunctions 的真正來源你可能會問為什么要弄的這么復(fù)雜?為了搞清楚這個問題,我們還需要繼續(xù)接觸完整的代碼。

下面我們繼續(xù)探索compileToFunctions是如何把模板字符串template編譯成渲染函數(shù)render的。

Vue.prototype.$mount函數(shù)體

回歸到Vue.prototype.$mount函數(shù)體內(nèi)。

var ref = compileToFunctions(template, {
	shouldDecodeNewlines: shouldDecodeNewlines,
	shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
	delimiters: options.delimiters,
	comments: options.comments
}, this);

在此傳遞給compileToFunctions的第一個參數(shù)就是模板字符串template,而第二個參數(shù)則是一個配置選項options。

先說說這些配置選項中的屬性!

shouldDecodeNewlines

源碼出處

// check whether current browser encodes a char inside attribute values
var div;
function getShouldDecode(href) {
	div = div || document.createElement('div');
	div.innerHTML = href ? "<a href=\"\n\"/>" : "<div a=\"\n\"/>";
	return div.innerHTML.indexOf('&#10;') > 0
}
// #3663: IE encodes newlines inside attribute values while other browsers don't
var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false;
// #6828: chrome encodes content in a[href]
var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false;

這個是什么意思呢?

大致的翻譯下,在我們innerHTML獲取內(nèi)容時,換行符和制表符分別被轉(zhuǎn)換成了&#10和&#9。在IE中,不僅僅是 a 標(biāo)簽的 href 屬性值,任何屬性值都存在這個問題。

這就會影響Vue的編譯器在對模板進行編譯后的結(jié)果,為了避免這些問題Vue需要知道什么時候要做兼容工作,如果 shouldDecodeNewlines 為 true,意味著 Vue 在編譯模板的時候,要對屬性值中的換行符或制表符做兼容處理。而shouldDecodeNewlinesForHref為true 意味著Vue在編譯模板的時候,要對a標(biāo)簽的 href 屬性值中的換行符或制表符做兼容處理。

options.delimiters & options.comments

兩者都是當(dāng)前Vue實例的$options屬性,并且delimiters和comments都是 Vue 提供的選項。

現(xiàn)在我們已經(jīng)搞清楚了這些配置選項是什么意思,那接下來我們把目光放在《Vue編譯器源碼分析(二)》針對compileToFunctions函數(shù)逐行分析。

compileToFunctions函數(shù)逐行分析

function createCompileToFunctionFn(compile) {
	var cache = Object.create(null);
	return function compileToFunctions(
		template,
		options,
		vm
	) {
		options = extend({}, options);
		var warn$$1 = options.warn || warn;
		delete options.warn;
		/* istanbul ignore if */
		{
			// detect possible CSP restriction
			try {
				new Function('return 1');
			} catch (e) {
				if (e.toString().match(/unsafe-eval|CSP/)) {
					warn$$1(
						'It seems you are using the standalone build of Vue.js in an ' +
						'environment with Content Security Policy that prohibits unsafe-eval. ' +
						'The template compiler cannot work in this environment. Consider ' +
						'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
						'templates into render functions.'
					);
				}
			}
		}
		// check cache
		var key = options.delimiters ?
			String(options.delimiters) + template :
			template;
		if (cache[key]) {
			return cache[key]
		}
		// compile
		var compiled = compile(template, options);
		// check compilation errors/tips
		{
			if (compiled.errors && compiled.errors.length) {
				warn$$1(
					"Error compiling template:\n\n" + template + "\n\n" +
					compiled.errors.map(function(e) {
						return ("- " + e);
					}).join('\n') + '\n',
					vm
				);
			}
			if (compiled.tips && compiled.tips.length) {
				compiled.tips.forEach(function(msg) {
					return tip(msg, vm);
				});
			}
		}
		// turn code into functions
		var res = {};
		var fnGenErrors = [];
		res.render = createFunction(compiled.render, fnGenErrors);
		res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
			return createFunction(code, fnGenErrors)
		});
		// check function generation errors.
		// this should only happen if there is a bug in the compiler itself.
		// mostly for codegen development use
		/* istanbul ignore if */
		{
			if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
				warn$$1(
					"Failed to generate render function:\n\n" +
					fnGenErrors.map(function(ref) {
						var err = ref.err;
						var code = ref.code;
						return ((err.toString()) + " in\n\n" + code + "\n");
					}).join('\n'),
					vm
				);
			}
		}
		return (cache[key] = res)
	}
}

注意compileToFunctions函數(shù)是接收三個參數(shù)的,第三個參數(shù)是當(dāng)前Vue實例。

首先:

options = extend({}, options);
var warn$$1 = options.warn || warn;
delete options.warn;

通過extend 把 options 配置對象上的屬性擴展一份到新對象上,定義warn$$1變量。warn是一個錯誤信息提示的函數(shù)。

接下來:

// detect possible CSP restriction
try {
	new Function('return 1');
} catch (e) {
	if (e.toString().match(/unsafe-eval|CSP/)) {
		warn$$1(
			'It seems you are using the standalone build of Vue.js in an ' +
			'environment with Content Security Policy that prohibits unsafe-eval. ' +
			'The template compiler cannot work in this environment. Consider ' +
			'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
			'templates into render functions.'
		);
	}
}

這段代碼使用 try catch 語句塊對 new Function('return 1') 這句代碼進行錯誤捕獲,如果有錯誤發(fā)生且錯誤的內(nèi)容中包含如 'unsafe-eval' 或者 'CSP' 這些字樣的信息時就會給出一個警告。

CSP全稱Content Security Policy ,可以直接翻譯為內(nèi)容安全策略,說白了,就是為了頁面內(nèi)容安全而制定的一系列防護策略. 通過CSP所約束的的規(guī)責(zé)指定可信的內(nèi)容來源(這里的內(nèi)容可以指腳本、圖片、iframe、fton、style等等可能的遠程的資源)。通過CSP協(xié)定,讓W(xué)EB處于一個安全的運行環(huán)境中。

如果你的策略比較嚴(yán)格,那么 new Function() 將會受到影響,從而不能夠使用。但是將模板字符串編譯成渲染函數(shù)又依賴 new Function(),所以解決方案有兩個:

  • 1、放寬你的CSP策略
  • 2、預(yù)編譯

這段代碼的作用就是檢測 new Function() 是否可用,并在某些極端情況下給你一個有用的提示。

接下來是:

var key = options.delimiters ?
	String(options.delimiters) + template :
	template;
if (cache[key]) {
	return cache[key]
}

options.delimiters這個選項是改變純文本插入分隔符,如果options.delimiters存在,則使用String 方法將其轉(zhuǎn)換成字符串并與 template 拼接作為 key 的值,否則直接使用 template 字符串作為 key 的值,然后判斷 cache[key] 是否存在,如果存在直接返回cache[key]。

這么做的目的是緩存字符串模板的編譯結(jié)果,防止重復(fù)編譯,提升性能,我們再看一下compileToFunctions函數(shù)的最后一句代碼:

return (cache[key] = res)

這句代碼在返回編譯結(jié)果的同時,將結(jié)果緩存,這樣下一次發(fā)現(xiàn)如果 cache 中存在相同的 key則不需要再次編譯,直接使用緩存的結(jié)果就可以了。

接下來:

// compile
var compiled = compile(template, options);
// check compilation errors/tips
if (compiled.errors && compiled.errors.length) {
	warn$$1(
		"Error compiling template:\n\n" + template + "\n\n" +
		compiled.errors.map(function(e) {
			return ("- " + e);
		}).join('\n') + '\n',
		vm
	);
   }
if (compiled.tips && compiled.tips.length) {
	compiled.tips.forEach(function(msg) {
		return tip(msg, vm);
	});
   }
}

compile 是引用了來自 createCompileToFunctionFn 函數(shù)的形參稍后會重點來介紹它。

在使用 compile 函數(shù)對模板進行編譯后會返回一個結(jié)果 compiled,返回結(jié)果 compiled 是一個對象且這個對象可能包含兩個屬性 errors 和 tips 。這兩個屬性分別包含了編譯過程中的錯誤和提示信息。所以上面那段代碼的作用就是用來檢查使用 compile 對模板進行編譯的過程中是否存在錯誤和提示的,如果存在那么需要將其打印出來。

接下來:

// turn code into functions
var res = {};
var fnGenErrors = [];
res.render = createFunction(compiled.render, fnGenErrors);
res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
	return createFunction(code, fnGenErrors)
});

res 是一個空對象且它是最終的返回值,fnGenErrors 是一個空數(shù)組。

在 res 對象上添加一個 render 屬性,這個 render 屬性,就是最終生成的渲染函數(shù),它的值是通過 createFunction 創(chuàng)建出來的。

createFunction 函數(shù)源碼

function createFunction(code, errors) {
	try {
		return new Function(code)
	} catch (err) {
		errors.push({
			err: err,
			code: code
		});
		return noop
	}
}

createFunction 函數(shù)接收兩個參數(shù),第一個參數(shù) code 為函數(shù)體字符串,該字符串將通過new Function(code) 的方式創(chuàng)建為函數(shù)。

第二個參數(shù) errors 是一個數(shù)組,作用是當(dāng)采用 new Function(code) 創(chuàng)建函數(shù)發(fā)生錯誤時用來收集錯誤的。

已知,傳遞給 createFunction 函數(shù)的第一個參數(shù)是 compiled.render,所以 compiled.render 應(yīng)該是一個函數(shù)體字符串,且我們知道 compiled 是 compile 函數(shù)的返回值,這說明:compile函數(shù)編譯模板字符串后所得到的是字符串形式的函數(shù)體。

傳遞給 createFunction 函數(shù)的第二個參數(shù)是之前聲明的 fnGenErrors 常量,也就是說當(dāng)創(chuàng)建函數(shù)出錯時的錯誤信息被 push 到這個數(shù)組里了。

在這句代碼之后,又在 res 對象上添加了 staticRenderFns 屬性:

res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
	return createFunction(code, fnGenErrors)
});

由這段代碼可知 res.staticRenderFns 是一個函數(shù)數(shù)組,是通過對compiled.staticRenderFns遍歷生成的,這說明:compiled 除了包含 render 字符串外,還包含一個字符串?dāng)?shù)組staticRenderFns ,且這個字符串?dāng)?shù)組最終也通過 createFunction 轉(zhuǎn)為函數(shù)。staticRenderFns 的主要作用是渲染優(yōu)化,我們后面詳細講解。

最后的代碼:

// check function generation errors.
// this should only happen if there is a bug in the compiler itself.
// mostly for codegen development use
/* istanbul ignore if */
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
	warn$$1(
		"Failed to generate render function:\n\n" +
		fnGenErrors.map(function(ref) {
			var err = ref.err;
			var code = ref.code;
			return ((err.toString()) + " in\n\n" + code + "\n");
		}).join('\n'),
		vm
	);
}
return (cache[key] = res)

這段代碼主要的作用是用來打印在生成渲染函數(shù)過程中的錯誤,返回結(jié)果的同時將結(jié)果緩存,接下來我們講講compile 的作用。

Vue編譯器源碼分析之compile解析

以上就是Vue編譯器源碼分析compileToFunctions作用詳解的詳細內(nèi)容,更多關(guān)于Vue編譯器compileToFunctions的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解基于element的區(qū)間選擇組件校驗(交易金額)

    詳解基于element的區(qū)間選擇組件校驗(交易金額)

    這篇文章主要介紹了詳解基于element的區(qū)間選擇組件校驗(交易金額),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • vue3頁面跳轉(zhuǎn)的兩種方式

    vue3頁面跳轉(zhuǎn)的兩種方式

    vue3的頁面跳轉(zhuǎn)有兩種方式,第一種是標(biāo)簽內(nèi)跳轉(zhuǎn),第二種是編程式路由導(dǎo)航,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2023-05-05
  • vue 父組件通過v-model接收子組件的值的代碼

    vue 父組件通過v-model接收子組件的值的代碼

    這篇文章主要介紹了vue 父組件通過v-model接收子組件的值的代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • Vue3配置axios跨域?qū)崿F(xiàn)過程解析

    Vue3配置axios跨域?qū)崿F(xiàn)過程解析

    這篇文章主要介紹了Vue3配置axios跨域?qū)崿F(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • vue3+ts 依賴注入provide inject的用法

    vue3+ts 依賴注入provide inject的用法

    vue3中引入新的組件傳值方式,就是provide/inject依賴注入模式,本文主要介紹了vue3+ts 依賴注入provide inject的用法,感興趣的可以了解一下
    2023-11-11
  • Vue3實現(xiàn)優(yōu)雅加載圖片的動畫效果

    Vue3實現(xiàn)優(yōu)雅加載圖片的動畫效果

    這篇文章主要為大家詳細介紹了Vue3如何實現(xiàn)加載圖片時添加一些動畫效果,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以參考下
    2023-10-10
  • Vue實現(xiàn)拖拽式分割布局

    Vue實現(xiàn)拖拽式分割布局

    這篇文章主要為大家詳細介紹了Vue實現(xiàn)拖拽式分割布局,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • vue中記錄滾動條位置的兩種方法

    vue中記錄滾動條位置的兩種方法

    最近用 Vue 做移動端頁面遇到一個問題,需要記住滾動條的位置,所以下面這篇文章主要給大家介紹了關(guān)于vue中記錄滾動條位置的兩種方法,文中給出了詳細的實例,需要的朋友可以參考下
    2023-01-01
  • 如何使用JS監(jiān)聽一個變量改變

    如何使用JS監(jiān)聽一個變量改變

    在JS編程中如果能監(jiān)測變量的內(nèi)容,當(dāng)變量值發(fā)生變化時,實時發(fā)出通知,這定是一項很有用的功能,下面這篇文章主要給大家介紹了關(guān)于如何使用JS監(jiān)聽一個變量改變的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • vue-prop父組件向子組件進行傳值的方法

    vue-prop父組件向子組件進行傳值的方法

    下面小編就為大家分享一篇vue-prop父組件向子組件進行傳值的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03

最新評論