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

資訊專欄INFORMATION COLUMN

詳細分析Vue.nextTick()實現(xiàn)

DevYK / 725人閱讀

摘要:因為平時使用都是傳回調(diào)的,所以很好奇什么情況下會為,去翻看官方文檔發(fā)現(xiàn)起新增如果沒有提供回調(diào)且在支持的環(huán)境中,則返回一個。這就對了,函數(shù)體內(nèi)最后的判斷很明顯就是這個意思沒有回調(diào)支持。

Firstly, this paper is based on Vue 2.6.8
剛開始接觸Vue的時候,哇nextTick好強,咋就在這里面寫就是dom更新之后,當(dāng)時連什么macrotask、microtask都不知道(如果你也不是很清楚,推薦點這里去看一下,也有助于你更好地理解本文),再后來,寫的多了看得多了愈發(fā)膨脹了,就想看看這個nextTick到底是咋實現(xiàn)的
一、源碼

???????關(guān)于vue中nextTick方法的實現(xiàn)位于vue源碼下的src/core/util/next-tick.js,(下文所提到的next-tick.js都是指這個文件)由于篇幅原因就不全粘過來了,下面隨著分析會貼出主要代碼片段。

二、分析

函數(shù)定義

將nextTick定義到Vue原型鏈上代碼位于src/core/instance/render.js,代碼如下

 Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
 }

上述代碼中return的nextTick就是我們本文主角,他的定義如下

export function nextTick (cb?: Function, ctx?: Object) { // next-tick.js line87
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, "nextTick")
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    timerFunc()
  }
  if (!cb && typeof Promise !== "undefined") {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

1)函數(shù)參數(shù)cb?: Function,意味參數(shù)cb(callback)的類型為函數(shù)或undefined,ctx(context)同理,這種類型判斷是TypeScript的寫法。
??????同時可以看到我們常用的this.$nextTick()已經(jīng) 在定義到原型鏈上時 給nextTick函數(shù)傳了ctx參數(shù)也就是指向當(dāng)前組件的this。(這句話好繞,暴露了自己的語文水平)
2)函數(shù)體內(nèi)callbacks是在next-tick.js line10定義的一個數(shù)組,判斷如果參數(shù)cb不為undefined,就把cb push到callbacks中,如果cb為undefined,則把_resolve(ctx)push到callbacks中。
??????因為平時使用都是傳回調(diào)的,所以很好奇cb什么情況下會為undefined,去翻看Vue官方文檔發(fā)現(xiàn):

2.1.0 起新增:如果沒有提供回調(diào)且在支持 Promise 的環(huán)境中,則返回一個 Promise。

??????這就對了,函數(shù)體內(nèi)最后的if判斷很明顯就是這個意思if (!cb && typeof Promise !== "undefined")沒有回調(diào)&&支持Promise。
??????在測試工程里寫如下代碼

created() {
  Vue.nextTick(undefined, { a: "in nextTick" }).then(ctx => {
    console.log(ctx.a)
  })
  console.log("out nextTick")
}

??????運行結(jié)果如下??????沒有任何問題(注意測試要使用Vue.nextTick而不是$nextTick,因為上文講到過$nextTick函數(shù)的ctx參數(shù)是當(dāng)前組件)
3) 函數(shù)體內(nèi)只剩下中間if (!pending),這段代碼很好懂,pending明顯是一個狀態(tài)位,而timerFunc()就應(yīng)該是nextTick實現(xiàn)異步的核心了

timerFunc

??????在代碼中搜索timerFunc發(fā)現(xiàn)除了聲明和nextTick函數(shù)中,還有四處使用timerFunc的代碼片段,這四處代碼片段被嵌套在一個大的if else判斷里

  if (typeof Promise !== "undefined" && isNative(Promise)) { // next-tick.js line42
    timerFunc = ...
  } else if (!isIE && typeof MutationObserver !== "undefined" && (
    isNative(MutationObserver) ||
    MutationObserver.toString() === "[object MutationObserverConstructor]"
  )) {
    timerFunc = ...
  } else if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
    timerFunc = ...
  } else {
    timerFunc = ...
  }

??????可以看到nextTick優(yōu)先使用microTask(Promise和MutationObserver)然后使用macroTask(setImmediate和setTimeout)這也符合尤大在2.6.0的更新日志中說的

next-tick: revert nextTick to alaways use microtask

??????首先這個alaways是不是拼錯了
??????不太對啊,我是不是對always有什么誤解,這不是明明還用macroTask的可能嗎
??????至于具體在不同的異步方式中是如何定義timerFunc的大同小異,如果仔細講解的話還要花費部分篇幅說明MutationObserver,畢竟我們的主角是nextTick,這里就不喧賓奪主,反正都是把timerFunc定義為在異步中調(diào)用flushCallbacks的函數(shù),而函數(shù)flushCallbacks的定義在源碼中如下

function flushCallbacks () { // next-tick.js line13
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}

?????? 因為callbacks里都是函數(shù),所以一層深拷貝的方式就可以滿足復(fù)制需求,定義一個copies數(shù)組等于callbacks,然后清空callbacks,然后遍歷copies數(shù)組調(diào)用其中的函數(shù)。

三、總結(jié)

??????nextTick實現(xiàn)流程大致是這樣的:

st=>operation: 將回調(diào)函數(shù)push到callbacks數(shù)組中
op=>operation: 調(diào)用timerFunc()根據(jù)不同情況采用不同異步方式調(diào)用flushCallbacks
e=>operation: 刷新callbacks數(shù)組,遍歷并調(diào)用其中所有函數(shù)
st->op->e

??????能看懂一部分Vue源碼對于我這種入行不到一年的萌新還是非常有成就感的一件事,但是還有兩個地方有些疑慮,上文也都有提及:

1) 箭頭函數(shù)不能改變this指向為什么使用nextTick的時候可以使用箭頭函數(shù),即nextTick函數(shù)定義中的cb.call(ctx)
2) 為什么更新日志中寫的是always use microtask,而我找到的源碼中是存在使用macroTask的情況的
??????后續(xù)將對問題的解決進行補充,也歡迎大佬在線評論傳道授業(yè)

2019/4/14
??????對于之前的兩個問題,我只能做出Vue本身使用了一部分babel的猜測,不過這兩個問題不影響整體邏輯的理解就是了

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

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

相關(guān)文章

  • Vue原理】NextTick - 源碼版 之 獨立自身

    摘要:盡量把所有異步代碼放在一個宏微任務(wù)中,減少消耗加快異步代碼的執(zhí)行。我們知道,如果一個異步代碼就注冊一個宏微任務(wù)的話,那么執(zhí)行完全部異步代碼肯定慢很多避免頻繁地更新。中就算我們一次性修改多次數(shù)據(jù),頁面還是只會更新一次。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5...

    劉東 評論0 收藏0
  • Vue源碼詳解之nextTick:MutationObserver只是浮云,microtask才是核

    摘要:后來尤雨溪了解到是將回調(diào)放入的隊列。而且瀏覽器內(nèi)部為了更快的響應(yīng)用戶,內(nèi)部可能是有多個的而的的優(yōu)先級可能更高,因此對于尤雨溪采用的,甚至可能已經(jīng)多次執(zhí)行了的,都沒有執(zhí)行的,也就導(dǎo)致了我們更新操 原發(fā)于我的博客。 前一篇文章已經(jīng)詳細記述了Vue的核心執(zhí)行過程。相當(dāng)于已經(jīng)搞定了主線劇情。后續(xù)的文章都會對其中沒有介紹的細節(jié)進行展開。 現(xiàn)在我們就來講講其他支線任務(wù):nextTick和micro...

    陳偉 評論0 收藏0
  • Vue.nextTick使用和源碼分析

    摘要:而中的回調(diào)函數(shù)則會在頁面渲染后才執(zhí)行。還使用方法復(fù)制數(shù)組并把數(shù)組清空,這里的數(shù)組就是存放主線程執(zhí)行過程中的函數(shù)所傳的回調(diào)函數(shù)集合主線程可能會多次使用方法。到這里就已經(jīng)實現(xiàn)了根據(jù)環(huán)境選擇異步方法,并在異步方法中依次調(diào)用傳入方法的回調(diào)函數(shù)。 Vue.nextTick的應(yīng)用場景 Vue 是采用異步的方式執(zhí)行 DOM 更新。只要觀察到數(shù)據(jù)變化,Vue 將開啟一個隊列,并緩沖同一事件循環(huán)中發(fā)生的...

    Jrain 評論0 收藏0
  • Vue源碼中的nextTick實現(xiàn)邏輯

    摘要:這是因為在運行時出錯,我們不這個錯誤的話,會導(dǎo)致整個程序崩潰掉。如果沒有向中傳入,并且瀏覽器支持的話,我們的返回的將是一個。如果不支持,就降低到用,整體邏輯就是這樣。。 我們知道vue中有一個api。Vue.nextTick( [callback, context] )他的作用是在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個方法,獲取更新后的 DOM。那么這個...

    Anshiii 評論0 收藏0

發(fā)表評論

0條評論

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