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

資訊專欄INFORMATION COLUMN

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

3403771864 / 539人閱讀

  這篇文章主要講述compileToFunctions的作用。

  我們現(xiàn)在就compileToFunctions 的真弄明白為什么要弄的這么復(fù)雜?現(xiàn)在我們看看下面完整代碼。

  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
  }, th

is);

  在上面可以看出,在此傳遞給compileToFunctions的第一個(gè)參數(shù)就是模板字符串template,而第二個(gè)參數(shù)則是一個(gè)配置選項(xiàng)options。

  先說(shuō)說(shuō)這些配置選項(xiàng)中的屬性!

  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;

  上面代碼想表達(dá)什么?

  其實(shí)大致表達(dá)是在我們innerHTML獲取內(nèi)容時(shí),換行符和制表符則轉(zhuǎn)化成&#10和&#9。在IE瀏覽器中,這個(gè)將不會(huì)成為問(wèn)題。

  但這會(huì)對(duì)Vue的編譯器在對(duì)模板進(jìn)行編譯后的結(jié)果有影響,如何不出現(xiàn)這就要Vue需要知道在什么時(shí)候要做兼容工作,如果 shouldDecodeNewlines 為 true,意味著 Vue 在編譯模板的時(shí)候,要對(duì)屬性值中的換行符或制表符做兼容處理。而shouldDecodeNewlinesForHref為true 意味著Vue在編譯模板的時(shí)候,要對(duì)a標(biāo)簽的 href 屬性值中的換行符或制表符做兼容處理。

  options.delimiters & options.comments

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

1.jpg

2.jpg

  現(xiàn)在我們已經(jīng)搞清楚了這些配置選項(xiàng)是什么意思,那接下來(lái)我們把目光放在《Vue編譯器源碼分析(二)》針對(duì)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ù)是接收三個(gè)參數(shù)的,第三個(gè)參數(shù)是當(dāng)前Vue實(shí)例。

  首先:

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

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

  接下來(lái):

  // 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.'
  );
  }
  }

  上面代碼體現(xiàn)出語(yǔ)句問(wèn)題就是使用 try catch 語(yǔ)句塊對(duì) new Function('return 1') 這句代碼進(jìn)行錯(cuò)誤捕獲,如果有錯(cuò)誤發(fā)生且錯(cuò)誤的內(nèi)容中包含如 'unsafe-eval' 或者 'CSP' 這些字樣的信息時(shí)就會(huì)給出一個(gè)警告。

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

  由于new Function() 被影響到,因此不可以使用。但是將模板字符串編譯成渲染函數(shù)又依賴new Function(),所以解決方案有兩個(gè):

  1、放寬你的CSP策略

  2、預(yù)編譯

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

  接下來(lái)是:

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

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

  這么做的目的是緩存字符串模板的編譯結(jié)果,防止重復(fù)編譯,提升性能,我們?cè)倏匆幌耤ompileToFunctions函數(shù)的最后一句代碼:

  return (cache[key] = res)

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

  接下來(lái):

 

 // 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 是引用了來(lái)自 createCompileToFunctionFn 函數(shù)的形參稍后會(huì)重點(diǎn)來(lái)介紹它。

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

  接下來(lái):

  // 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 是一個(gè)空對(duì)象且它是最終的返回值,fnGenErrors 是一個(gè)空數(shù)組。

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

  createFunction 函數(shù)源碼

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

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

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

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

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

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

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

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

  最后的代碼:

  // 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ù)過(guò)程在打印中的錯(cuò)誤,且同時(shí)將結(jié)果村存儲(chǔ)下來(lái),接下來(lái)我們講講compile 的作用。


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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/127790.html

相關(guān)文章

  • Vue原理】Compile - 源碼版 之 從新建實(shí)例到 compile結(jié)束的主要流程

    摘要:頁(yè)面這個(gè)實(shí)例,按理就需要解析兩次,但是有緩存之后就不會(huì)理清思路也就是說(shuō),其實(shí)內(nèi)核就是不過(guò)是經(jīng)過(guò)了兩波包裝的第一波包裝在中的內(nèi)部函數(shù)中內(nèi)部函數(shù)的作用是合并公共和自定義,但是相關(guān)代碼已經(jīng)省略,另一個(gè)就是執(zhí)行第二波包裝在中,目的是進(jìn)行緩存 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 ...

    CODING 評(píng)論0 收藏0
  • 聊聊Vue.js的template編譯

    摘要:具體可以查看抽象語(yǔ)法樹(shù)。而則是帶緩存的編譯器,同時(shí)以及函數(shù)會(huì)被轉(zhuǎn)換成對(duì)象。會(huì)用正則等方式解析模板中的指令等數(shù)據(jù),形成語(yǔ)法樹(shù)。是將語(yǔ)法樹(shù)轉(zhuǎn)化成字符串的過(guò)程,得到結(jié)果是的字符串以及字符串。里面的節(jié)點(diǎn)與父節(jié)點(diǎn)的結(jié)構(gòu)類似,層層往下形成一棵語(yǔ)法樹(shù)。 寫(xiě)在前面 因?yàn)閷?duì)Vue.js很感興趣,而且平時(shí)工作的技術(shù)棧也是Vue.js,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。 文...

    gnehc 評(píng)論0 收藏0
  • vue源碼閱讀之?dāng)?shù)據(jù)渲染過(guò)程

    摘要:圖在中應(yīng)用三數(shù)據(jù)渲染過(guò)程數(shù)據(jù)綁定實(shí)現(xiàn)邏輯本節(jié)正式分析從到數(shù)據(jù)渲染到頁(yè)面的過(guò)程,在中定義了一個(gè)的構(gòu)造函數(shù)。一、概述 vue已是目前國(guó)內(nèi)前端web端三分天下之一,也是工作中主要技術(shù)棧之一。在日常使用中知其然也好奇著所以然,因此嘗試閱讀vue源碼并進(jìn)行總結(jié)。本文旨在梳理初始化頁(yè)面時(shí)data中的數(shù)據(jù)是如何渲染到頁(yè)面上的。本文將帶著這個(gè)疑問(wèn)一點(diǎn)點(diǎn)追究vue的思路??傮w來(lái)說(shuō)vue模版渲染大致流程如圖1所...

    AlphaGooo 評(píng)論0 收藏0
  • Vue編程三部曲之將template編譯成AST示例詳解

      知道嗎?Vue.js 有 2 個(gè)版本,一個(gè)是Runtime + Compiler版本,另一個(gè)是Runtime only版本。Runtime + Compiler版本是包含編譯代碼的,簡(jiǎn)單來(lái)說(shuō)就是Runtime only版本不包含編譯代碼的,在運(yùn)行時(shí)候,需要借助 webpack 的 vue-loader 事先把模板編譯成 render 函數(shù)?! 〖偃缭谀阈枰诳蛻舳司幾g模板 (比如傳入一個(gè)字符串...

    3403771864 評(píng)論0 收藏0
  • vue源碼分析系列之入口文件分析

    摘要:中引入了中的中引入了中的中,定義了的構(gòu)造函數(shù)中的原型上掛載了方法,用來(lái)做初始化原型上掛載的屬性描述符,返回原型上掛載的屬性描述符返回原型上掛載與方法,用來(lái)為對(duì)象新增刪除響應(yīng)式屬性原型上掛載方法原型上掛載事件相關(guān)的方法。 入口尋找 入口platforms/web/entry-runtime-with-compiler中import了./runtime/index導(dǎo)出的vue。 ./r...

    kgbook 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<