国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

vue原理Compile之optimize標(biāo)記靜態(tài)節(jié)點(diǎn)源碼示例

3403771864 / 439人閱讀

  引言

  optimize的內(nèi)容雖然不多,但十分重要,它是一個(gè)更新性能優(yōu)化,現(xiàn)在來(lái)說(shuō)說(shuō):

  首先找到optimize位置,就在 parse 處理完之后,generate 之前

  var ast = parse(template.trim(), options);
  if (options.optimize !== false) {
  optimize(ast, options);
  }
  var code = generate(ast, options);

  上面這段代碼在函數(shù) baseCompile 中,如果想了解的,看這里Compile - 從新建實(shí)例到 compile結(jié)束的主要流程

  而 optimize 的作用是什么呢?

  Vue官方注釋

  優(yōu)化器的目標(biāo)

  遍歷生成的模板AST樹(shù),檢測(cè)純靜態(tài)的子樹(shù),即永遠(yuǎn)不需要更改的DOM。

  一旦我們檢測(cè)到這些子樹(shù),我們可以:

  1、將它們變成常數(shù),就是為了在每次重新渲染時(shí)不需要再為它們創(chuàng)建新的節(jié)點(diǎn)

  2、在修補(bǔ)過(guò)程中完全跳過(guò)它們。

  那是怎么做的呢?

  給靜態(tài)ast節(jié)點(diǎn)設(shè)置屬性 static,當(dāng)節(jié)點(diǎn)時(shí)靜態(tài)是

  el.static = true

  下面就來(lái)看下源碼

  function optimize(root, options) {
  if (!root) return
  // first pass: mark all non-static nodes.
  markStatic$1(root);
  // second pass: mark static roots.
  markStaticRoots(root);
  }

  里面主要調(diào)用了兩個(gè)函數(shù),這兩個(gè)函數(shù)會(huì)分別分析

  但是在此之前,我們先來(lái)看一個(gè)函數(shù),這個(gè)函數(shù)就是 判斷靜態(tài)節(jié)點(diǎn)的 主力函數(shù)

  直接傳入 ast 節(jié)點(diǎn),各種組合判斷,然后給 ast 節(jié)點(diǎn)添加上 static 屬性

  function isStatic(node) {
  // 文字表達(dá)式
  if (node.type === 2) return false
  // 純文本
  if (node.type === 3) return true
  return (
  // 設(shè)置了 v-pre 指令,表示不用解析
  node.pre ||
  (
  !node.hasBindings && // 沒(méi)有動(dòng)態(tài)綁定
  ! node.if && !node.for && // 不存在v-if ,v-for 指令
  ! ['slot','component'].indexOf(node.tag)>-1 && // 需要編譯的標(biāo)簽
  isPlatformReservedTag(node.tag) && // 正常html 標(biāo)簽
  ! isDirectChildOfTemplateFor(node) &&
  Object.keys(node).every(isStaticKey)
  )
  )
  }

  如果要判斷為靜態(tài)節(jié)點(diǎn),就要經(jīng)過(guò)下面7個(gè)條件的審判(把上面的代碼列了出來(lái))

  1 是否存在 v-pre

  如果添加了指令 v-pre,那么 node.pre 為 true,表明所有節(jié)點(diǎn)都不用解析了

  2 不能存在 node.hasBindings

  當(dāng)節(jié)點(diǎn)有綁定 Vue屬性的時(shí)候,比如指令,事件等,node.hasBindings 會(huì)為 true

  3 不能存在 node.if 和 node.for

  同樣,當(dāng) 節(jié)點(diǎn)有 v-if 或者 v-for 的時(shí)候,node.if 或者 node.for 為true

  4 節(jié)點(diǎn)名稱不能是slot 或者 component

  因?yàn)檫@兩者是要?jiǎng)討B(tài)編譯的,不屬于靜態(tài)范疇

  所以只要是 slot 或者 component 都不可能是靜態(tài)節(jié)點(diǎn)

  5 isPlatformReservedTag(node.tag)

  isPlatformReservedTag 是用于判斷該標(biāo)簽是否是正常的HTML 標(biāo)簽,有什么標(biāo)簽?zāi)兀?/p>

  標(biāo)簽必須是正常HTML標(biāo)簽,如下

  html,body,base,head,link,meta,style,title

  address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section

  div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul

  a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby

  s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video

  embed,object,param,source,canvas,script,noscript,del,ins

  caption,col,colgroup,table,thead,tbody,td,th,tr

  button,datalist,section,form,input,label,legend,meter,optgroup,option

  output,progress,select,textarea

  details,dialog,menu,menuitem,summary

  content,element,shadow,template,blockquote,iframe,tfoot

  svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face

  foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern

  polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view

  是不是挺多的,哈哈,尤大真厲害,估計(jì)收集了很多,我覺(jué)得應(yīng)該有用,就全放上來(lái)了

  6 isDirectChildOfTemplateFor(node)

  看下這個(gè)函數(shù)的源碼

  function isDirectChildOfTemplateFor(node) {
  while (node.parent) {
  node = node.parent;
  if (node.tag !== 'template') {
  return false
  }
  if (node.for) {
  return true
  }
  }
  return false
  }

  表明了節(jié)點(diǎn)父輩以上所有節(jié)點(diǎn)不能是 template 或者 帶有 v-for

  7 Object.keys(node).every(isStaticKey)

  isStaticKey是一個(gè)函數(shù),用于判斷傳入的屬性是否在下面的范圍內(nèi)

  type,tag,attrsList,attrsMap,plain,parent,children,attrs

  比如這樣的 ast

  <div style="" ></div>
  {
  attrsList: []
  attrsMap: {style: ""}
  children: []
  parent: undefined
  plain: false
  tag: "div"
  type: 1
  }

  這段代買(mǎi)就是表達(dá)ast 的所有屬性通過(guò) isStaticKey 判斷之后,會(huì)在上面逐一列出的屬性范圍中,且是靜態(tài)屬性,因此,這是靜態(tài)節(jié)點(diǎn)

  而當(dāng)你存在之外的其他屬性的時(shí)候,這個(gè)節(jié)點(diǎn)就不是靜態(tài)ast

  然后下面就來(lái)看 optimize 中出現(xiàn)的兩個(gè)函數(shù)把

  markStatic$1 和 markStaticRoot

  標(biāo)記靜態(tài)節(jié)點(diǎn)

  怎么標(biāo)記一個(gè)節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)呢,就在 markStatic$1 中進(jìn)行處理

   // 標(biāo)記節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)
  function markStatic$1(node) {
  node.static = isStatic(node);
  if (node.type !== 1) return
  // 不要將組件插槽內(nèi)容設(shè)置為靜態(tài)。
  // 這就避免了
  // 1、組件無(wú)法更改插槽節(jié)點(diǎn)
  // 2、靜態(tài)插槽內(nèi)容無(wú)法熱加載
  if (
  // 正常 thml 標(biāo)簽 才往下處理,組件之類的就不可以
  !isPlatformReservedTag(node.tag) &&
  // 標(biāo)簽名是 slot 才往下處理
  node.tag !== 'slot' &&
  // 有 inline-tempalte 才往下處理
  node.attrsMap['inline-template'] == null
  ) {
  return
  }
  // 遍歷所有孩子,如果孩子 不是靜態(tài)節(jié)點(diǎn),那么父親也不是靜態(tài)節(jié)點(diǎn)
  var l = node.children.length
  for (var i = 0;i < l; i++) {
  var child = node.children[i];
  // 遞歸設(shè)置子節(jié)點(diǎn),子節(jié)點(diǎn)再調(diào)用子節(jié)點(diǎn)
  markStatic$1(child);
  if (!child.static) {
  node.static = false;
  }
  }
  if (node.ifConditions) {
  var c = node.ifConditions.length
  for (var j = 1; j < c; j++) {
  // block 是 節(jié)點(diǎn)的 ast
  var block = node.ifConditions[j].block;
  markStatic$1(block);
  if (!block.static) {
  node.static = false;
  }
  }
  }
  }

  這個(gè)方法做了下面三種事情

  1 isStatic 這個(gè)方法對(duì) ast 節(jié)點(diǎn)本身進(jìn)行初步判斷

  進(jìn)行初步靜態(tài)節(jié)點(diǎn)判斷

  2 判斷靜態(tài)節(jié)點(diǎn)的額外的處理

  給節(jié)點(diǎn)本身判斷完是否靜態(tài)節(jié)點(diǎn)之后,就需要檢查所有的子孫節(jié)點(diǎn)。后面就是逐層遞歸子節(jié)點(diǎn),如果某子節(jié)點(diǎn)不是靜態(tài)節(jié)點(diǎn),那么父節(jié)點(diǎn)就不能是靜態(tài)節(jié)點(diǎn),現(xiàn)在就說(shuō)說(shuō)這樣的節(jié)點(diǎn)處理,其實(shí)并不是所有節(jié)點(diǎn)都會(huì)進(jìn)行特殊處理,是有條件的

  節(jié)點(diǎn)類型是 1

  類型 1 是 標(biāo)簽元素

  類型 2 是 文字表達(dá)式

  類型 3 是 純文本

  3 是正常 html 標(biāo)簽,標(biāo)簽是 slot,存在 inline-template 屬性

  1、必須是正常標(biāo)簽,也就是說(shuō)自定義標(biāo)簽不需要再次處理

  2、slot 會(huì)額外處理

  3、有 inline-template 屬性也會(huì)額外處理

  只有有一個(gè)滿足,就會(huì)進(jìn)行額外處理

  疑點(diǎn)

  你可以看到源碼中的最后一步

  判斷 node.ifCondition,并且如果 ifCondition 中保存的節(jié)點(diǎn)不是靜態(tài)的話,那么這個(gè) node 也不是靜態(tài)節(jié)點(diǎn)

  這個(gè)判斷就很讓我匪夷所思了

  明明如果存在 v-if 的話,該節(jié)點(diǎn)在 一開(kāi)始的 isStatic 中,就會(huì)被設(shè)置 node.static 為 false 了

  為什么還要在末尾 再判斷一遍呢?

  這里多余的一步,但為保證正常運(yùn)行還是加入在里面。

  經(jīng)過(guò)這一步,所有的節(jié)點(diǎn),都會(huì)被添加上 static 屬性,節(jié)點(diǎn)是否靜態(tài),一看便知

  標(biāo)記靜態(tài)根節(jié)點(diǎn)

  // 標(biāo)記根節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)
  function markStaticRoots(node) {
  if (node.type === 1) return
  // 要使一個(gè)節(jié)點(diǎn)符合靜態(tài)根的條件,它應(yīng)該有這樣的子節(jié)點(diǎn)
  // 不僅僅是靜態(tài)文本。否則,吊裝費(fèi)用將會(huì)增加
  // 好處大于好處,最好總是保持新鮮。
  if (
  // 靜態(tài)節(jié)點(diǎn)
  node.static &amp;&amp;
  // 有孩子
  node.children.length &amp;&amp;
  // 孩子有很多,或者第一個(gè)孩子不是純文本
  ! (node.children.length === 1
  &amp;&amp; node.children[0].type === 3
  )
  ) {
  node.staticRoot = true;
  return
  }
  else {
  node.staticRoot = false;
  }
  if (node.children) {
  var l = node.children.length
  for (var i = 0; i &lt; l; i++) {
  markStaticRoots(
  node.children[i]
  );
  }
  }
  }

  這樣也只是可以尋找 靜態(tài)的根節(jié)點(diǎn),應(yīng)該說(shuō)是區(qū)域根節(jié)點(diǎn)吧,反正一個(gè)節(jié)點(diǎn)下面有馬仔節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)就算是根節(jié)點(diǎn)。

  遞歸他的所有子孫,由此判斷哪個(gè)是靜態(tài)根節(jié)點(diǎn),如果是靜態(tài)ast,就會(huì)被添加上 staticRoot 這個(gè)屬性

  markStaticRoots 也是遞歸調(diào)用的,但是并不是會(huì)處理到所有節(jié)點(diǎn)

  因?yàn)檎业揭粋€(gè)根節(jié)點(diǎn)是靜態(tài)根節(jié)點(diǎn)后,就不會(huì)遞歸處理他的子節(jié)點(diǎn)了

  然后我們需要了解兩個(gè)問(wèn)題

  1、markStaticRoot 和 markStatic$1 的區(qū)別

  2、判斷靜態(tài)根節(jié)點(diǎn)的依據(jù)是什么

  markStaticRoots 和 markStatic$1 有什么區(qū)別?

  找出靜態(tài)根節(jié)點(diǎn)才是性能優(yōu)化的最終作用者

  markStatic$1 這個(gè)函數(shù)只是為 markStaticRoots 服務(wù)的,是為了先把每個(gè)節(jié)點(diǎn)都處理之后,更加方便快捷靜態(tài)根節(jié)點(diǎn),可以說(shuō)是把功能分開(kāi),這樣處理的邏輯就更清晰了

  劃分好之后,就只用找 部分的根節(jié)點(diǎn)(區(qū)域負(fù)責(zé)人就好了)

  這個(gè)就是因?yàn)閙arkStatic$1 添加的 static 屬性,我全局搜索,并沒(méi)有在處理DOM和 生成 render上使用過(guò)

  而 markStaticRoots 添加的 staticRoot ,在生成 render 上使用了

  而且再 根據(jù) markStaticRoots 寫(xiě)的功能邏輯 并 使用了 static 屬性進(jìn)行判斷

  所以我認(rèn)為 markStatic$1 是為 markStaticRoots 服務(wù)的一個(gè)函數(shù)

  被判斷為靜態(tài)根節(jié)點(diǎn)的條件是什么?

  1該節(jié)點(diǎn)的所有子孫節(jié)點(diǎn)都是靜態(tài)節(jié)點(diǎn)

  而 node.static = true 則表明了其所有子孫都是靜態(tài)的,否則上一步就被設(shè)置為 false 了

  2必須存在子節(jié)點(diǎn)

  3子節(jié)點(diǎn)不能只有一個(gè) 純文本節(jié)點(diǎn)

  簡(jiǎn)單來(lái)說(shuō)就是這個(gè)只有一個(gè)純文本子節(jié)點(diǎn)時(shí),這個(gè)點(diǎn)不能是靜態(tài)根節(jié)點(diǎn)。且只有純文本子節(jié)點(diǎn)時(shí),他是靜態(tài)節(jié)點(diǎn),但是不是靜態(tài)根節(jié)點(diǎn)。靜態(tài)根節(jié)點(diǎn)是optimize 優(yōu)化的條件,沒(méi)有靜態(tài)根節(jié)點(diǎn),說(shuō)明這部分不會(huì)被優(yōu)化

  注意在Vue 官方說(shuō)明中寫(xiě)的是,如果子節(jié)點(diǎn)只有一個(gè)純文本節(jié)點(diǎn),如果優(yōu)化的話,帶來(lái)的成本就比好處多了,因此,選擇不優(yōu)化

  但為什么子節(jié)點(diǎn)只有是靜態(tài)文本時(shí),成本會(huì)大?現(xiàn)在來(lái)說(shuō)說(shuō)我個(gè)人的看法:

  首先,優(yōu)化不僅可以減少DOM比對(duì),而且可以提升加速更新

  而帶來(lái)的成本是什么呢?

  1、維護(hù)靜態(tài)模板存儲(chǔ)對(duì)象

  2、多層函數(shù)調(diào)用

  現(xiàn)在我們來(lái)簡(jiǎn)單解釋下上面兩種成本

  1 維護(hù)靜態(tài)模板存儲(chǔ)對(duì)象

  首先所有的靜態(tài)根節(jié)點(diǎn) 都會(huì)被解析生成 VNode,并且被存在一個(gè)緩存對(duì)象中,就在 Vue.proto._staticTree 中,比如下面這個(gè)靜態(tài)模板

1.png

  之后就解析,且存進(jìn)去

2.png

  但逐漸存儲(chǔ)內(nèi)容越多,越大,占用空間就成為問(wèn)題。減少儲(chǔ)存成為必須,所有只有純文本的靜態(tài)根節(jié)點(diǎn)就被排除了

  2 多層函數(shù)調(diào)用

  這個(gè)問(wèn)題涉及到 render 和 靜態(tài) render 的合作

  舉個(gè)例子

  一個(gè)動(dòng)態(tài)跟靜態(tài)混合的模板

3.png

  生成的 render 函數(shù)是這樣的

  with(this) {
  return _c('div', [
  _m(0),
  ( testStaticRender) ? _c('span') : _e()
  ])
  }

  看到 _m(0) 了嗎,這個(gè)函數(shù)就是去獲取靜態(tài)模板的。現(xiàn)在說(shuō)說(shuō),態(tài)模板的處理,就多了一個(gè) _m 函數(shù)的調(diào)用,加上初期涉及到了很多函數(shù)的處理,其中包括上一步的存儲(chǔ),之后再去,既然純文本節(jié)點(diǎn)不做優(yōu)化,這樣就說(shuō)明更新時(shí)需要比對(duì)這部分嘍?

  但是純文本的比對(duì),就是直接 比較字符串 是否相等而已啊

  消耗簡(jiǎn)直不要太小,那么這樣,我還有必要去維護(hù)多一個(gè)靜態(tài)模板緩存嗎?

  其實(shí)總來(lái)說(shuō)就是:

  只有純文本子節(jié)點(diǎn)最好不要當(dāng)做靜態(tài)模板處理

4.png

  可以看到模板放在了 staticRenderFns 上,做了靜態(tài)模板處理

5.png

  看到了吧。消耗大了吧.

  更新的時(shí)候,會(huì)比較 div 和 span 和 span 內(nèi)的純文本

  vue原理Compile之optimize標(biāo)記靜態(tài)節(jié)點(diǎn)源碼示例的詳細(xì)內(nèi)容講述完畢,歡迎大家看后續(xù)精彩內(nèi)容。


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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/127837.html

相關(guān)文章

  • Vue原理Compile - 源碼 optimize 標(biāo)記靜態(tài)節(jié)點(diǎn)

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

    Soarkey 評(píng)論0 收藏0
  • Vue原理Compile - 白話版

    摘要:寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理白話版終于到了要講白話的時(shí)候了 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究...

    dingding199389 評(píng)論0 收藏0
  • JS每日一題:簡(jiǎn)述一下Vue.js的template編譯過(guò)程?

    摘要:?jiǎn)柡?jiǎn)述一下的編譯過(guò)程先上一張圖大致看一下整個(gè)流程從上圖中我們可以看到是從后開(kāi)始進(jìn)行中整體邏輯分為三個(gè)部分解析器將模板字符串轉(zhuǎn)換成優(yōu)化器對(duì)進(jìn)行靜態(tài)節(jié)點(diǎn)標(biāo)記,主要用來(lái)做虛擬的渲染優(yōu)化代碼生成器使用生成函數(shù)代碼字符串開(kāi)始前先解釋一下抽象 20190215問(wèn) 簡(jiǎn)述一下Vue.js的template編譯過(guò)程? 先上一張圖大致看一下整個(gè)流程showImg(https://image-static....

    NicolasHe 評(píng)論0 收藏0
  • FE.SRC-Vue實(shí)戰(zhàn)與原理筆記

    摘要:超出此時(shí)間則渲染錯(cuò)誤組件。元素節(jié)點(diǎn)總共有種類型,為表示是普通元素,為表示是表達(dá)式,為表示是純文本。 實(shí)戰(zhàn) - 插件 form-validate {{ error }} ...

    wangjuntytl 評(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

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

0條評(píng)論

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