成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

VueJS源碼學(xué)習(xí)——MutationObserver實(shí)現(xiàn)nextTick

xumenger / 2834人閱讀

摘要:倡導(dǎo)開(kāi)發(fā)者盡量不直接操作,但有的時(shí)候由于各種需求讓開(kāi)發(fā)者不得不這樣做,于是的實(shí)現(xiàn)就是讓開(kāi)發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的數(shù)據(jù)。

Vue 倡導(dǎo)開(kāi)發(fā)者盡量不直接操作 DOM,但有的時(shí)候由于各種需求讓開(kāi)發(fā)者不得不這樣做,于是 nextTick 的實(shí)現(xiàn)就是讓開(kāi)發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到 DOM 后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的 DON 數(shù)據(jù)。

原文地址
項(xiàng)目地址

那么如何實(shí)現(xiàn) nextTick呢,我們首先可以想到的是利用 setTimeout 的異步回調(diào)來(lái)實(shí)現(xiàn),不過(guò)由于各個(gè)瀏覽器的不同,setTimeout 的延遲很高,因此在 nextTick 中只作為最后的備胎,首選的方案則是 MutationObserver(在后面的內(nèi)容中 MO 代表 MutationObserver)

nextTick 的源碼實(shí)現(xiàn)
export const nextTick = (function () {
  var callbacks = []
  var pending = false
  var timerFunc
  function nextTickHandler () {
    pending = false
    var copies = callbacks.slice(0)
    callbacks = []
    for (var i = 0; i < copies.length; i++) {
      copies[i]()
    }
  }
  /* istanbul ignore if */
  if (typeof MutationObserver !== "undefined") { // 首選 MutationObserver 
    var counter = 1
    var observer = new MutationObserver(nextTickHandler) // 聲明 MO 和回調(diào)函數(shù)
    var textNode = document.createTextNode(counter)
    observer.observe(textNode, { // 監(jiān)聽(tīng) textNode 這個(gè)文本節(jié)點(diǎn)
      characterData: true // 一旦文本改變則觸發(fā)回調(diào)函數(shù) nextTickHandler
    })
    timerFunc = function () {
      counter = (counter + 1) % 2 // 每次執(zhí)行 timeFunc 都會(huì)讓文本在 1 和 0 間切換
      textNode.data = counter
    }
  } else {
    timerFunc = setTimeout // 如果不支持 MutationObserver, 退選 setTimeout
  }
  return function (cb, ctx) {
    var func = ctx
      ? function () { cb.call(ctx) }
      : cb
    callbacks.push(func)
    if (pending) return
    pending = true
    timerFunc(nextTickHandler, 0)
  }
})()
MutationObserver 的功能和作用

MO 給開(kāi)發(fā)者提供了一種能在某個(gè)范圍內(nèi)的DOM數(shù)發(fā)生變化時(shí)作出適當(dāng)反應(yīng)的能力 ——MDN

用人話說(shuō)是開(kāi)發(fā)者能通過(guò)它創(chuàng)建一個(gè)觀察者對(duì)象,這個(gè)對(duì)象會(huì)監(jiān)聽(tīng)某個(gè)DOM元素,并在它的DOM樹(shù)發(fā)生變化時(shí)執(zhí)行我們提供的回調(diào)函數(shù)。

具體參考這個(gè) DEMO

比較特別的是實(shí)例化的時(shí)候需要先傳入回調(diào)函數(shù):

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  })
})

然后才配置觀察選項(xiàng),包括觀察節(jié)點(diǎn)和觀察的屬性:

// 選擇目標(biāo)節(jié)點(diǎn)
var target = document.querySelector("#some-id");
 
// 配置觀察選項(xiàng):
var config = { attributes: true, childList: true, characterData: true }
 
// 傳入目標(biāo)節(jié)點(diǎn)和觀察選項(xiàng)
observer.observe(target, config);
 
// 隨后,你還可以停止觀察
observer.disconnect();

對(duì)于老版本的谷歌和火狐,則需要使用帶前綴的 MO:

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
MutationObserver 和 microtask

那么為什么優(yōu)選使用 MutationObserver呢?

一開(kāi)始以為是 MO 就是用來(lái)監(jiān)聽(tīng) DOM 變化的,那么使用 textnode 模擬 DOM 變化再利用 MO 來(lái)監(jiān)聽(tīng)觸發(fā)從而實(shí)現(xiàn) nextTick 不就很適合,直到了解看到了知乎上的問(wèn)答才知道是因?yàn)?MO 會(huì)比 setTimeout 早執(zhí)行的緣故,

這里需要了解JS的運(yùn)行運(yùn)行機(jī)制(重新刷新了我的三觀), JS 的事件運(yùn)行機(jī)制執(zhí)行的時(shí)候會(huì)區(qū)分 taskmicrotask, 引擎在每個(gè) task 執(zhí)行完畢,并在從隊(duì)列里取下一個(gè)task來(lái)執(zhí)行之前, 執(zhí)行完所有的 microtask 隊(duì)列中的 microtask


(task 和 microtask 摘自 https://jakearchibald.com/)

setTimeout 回調(diào)會(huì)被分配到一個(gè)新的task中等待執(zhí)行,而 Promise 的 resolver、MO 的 回調(diào)都會(huì)被分配到 microtask 的隊(duì)列中,所以會(huì)比 setTimout 先執(zhí)行

除了比 setTimout 快之外,還有 渲染性能 的問(wèn)題,根據(jù)HTML Standard, 每個(gè) task 運(yùn)行完以后, UI 都會(huì)重新渲染,那么在 microtask 中就完成數(shù)據(jù)更新, 當(dāng)前 task 結(jié)束就可以得到最新的 UI, 反之如果新建一個(gè) task 來(lái)做數(shù)據(jù)更新,那么渲染就會(huì)進(jìn)行兩次。

所以性?xún)r(jià)比如此高的 MO 自然成為了首選

關(guān)于 microtask,具體可以閱讀 Jake 寫(xiě)的 Tasks, microtasks, queues and schedules

nextTick 的版本迭代

上面關(guān)于 nextTick 的源碼實(shí)現(xiàn)屬于 vue 最早的版本 v1.0.9,在深挖 mutationObserver 的時(shí)候發(fā)現(xiàn) nextTick 在vue的版本迭代中也在不斷的進(jìn)化,同事也發(fā)生過(guò)退化,非常有趣:

先說(shuō)說(shuō)退化的事件,尤大(vue的作者)曾經(jīng)使用 window.postMessage 來(lái)替代 MO 實(shí)現(xiàn) nextTick,結(jié)果開(kāi)發(fā)者使用后發(fā)現(xiàn)了問(wèn)題,可以看看這兩個(gè) JSFiddle:jsfiddle1 和 jsfiddle2, 兩個(gè)例子用了不同版本來(lái)實(shí)現(xiàn)元素的絕對(duì)定位,第一個(gè)使用的是 2.0.0-rc6,這個(gè)版本采用的是 MO,而后來(lái)因?yàn)?IOS 9.3 的 WebView 里 MO 有 bug,尤大便換成 window.postMessage來(lái)實(shí)現(xiàn),即第二個(gè)實(shí)例版本為 2.0.0-rc7, 但是由于 postMessage 會(huì)將回調(diào)放到 macrotask 其實(shí)也就是 task 里面,導(dǎo)致可能執(zhí)行了多次 UI 的task都沒(méi)有執(zhí)行 window.postMessage 的 task,也就延遲了更新DOM操作的時(shí)間。尤大在后續(xù)版本撤回了這一次修改,具體的討論可以看issue

關(guān)于進(jìn)化,在后續(xù)的版本里,由于 es6 的新語(yǔ)法,nextTick 開(kāi)始使用 Promise.then 和 MO 來(lái)做首選和次選,在前面的討論中已經(jīng)提到,Promise.then 也屬于 microtask。

資源

MutationObserver MDN

Tasks, microtasks, queues and schedules

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

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

相關(guān)文章

  • VueJS源碼學(xué)習(xí)——元素在插入和移出 dom 時(shí)的過(guò)渡邏輯

    摘要:原文地址項(xiàng)目地址關(guān)于中使用效果,官網(wǎng)上的解釋如下當(dāng)元素插入到樹(shù)或者從樹(shù)中移除的時(shí)候,屬性提供變換的效果,可以使用來(lái)定義變化效果,也可以使用來(lái)定義首先第一個(gè)函數(shù)是將元素插入,函數(shù)實(shí)現(xiàn)調(diào)用了實(shí)現(xiàn)代碼如下寫(xiě)的好的代碼就是文檔,從注釋和命名上就 src/transition 原文地址項(xiàng)目地址 關(guān)于 vue 中使用 transition 效果,官網(wǎng)上的解釋如下: With Vue.js’ tra...

    Dogee 評(píng)論0 收藏0
  • VueJS源碼學(xué)習(xí)——工具類(lèi)函數(shù)實(shí)現(xiàn)(二)

    摘要:它被當(dāng)做一個(gè)輕量版本的使用,用于存儲(chǔ)已排好版的或尚未打理好格式的片段。最大的區(qū)別是因?yàn)椴皇钦鎸?shí)樹(shù)的其中一部分,它的變化不會(huì)引起樹(shù)的重新渲染的操作,或者導(dǎo)致性能影響的問(wèn)題出現(xiàn)。 原文地址項(xiàng)目地址 工具類(lèi) /** * Simple bind, faster than native * * @param {Function} fn * @param {Object} ctx * @...

    fish 評(píng)論0 收藏0
  • 從Vue.js源碼看異步更新DOM策略及nextTick

    摘要:我們發(fā)現(xiàn)默認(rèn)是使用異步執(zhí)行更新。優(yōu)先使用,在不存在的情況下使用,這兩個(gè)方法的回調(diào)函數(shù)都會(huì)在中執(zhí)行,它們會(huì)比更早執(zhí)行,所以?xún)?yōu)先使用。是最后的一種備選方案,它會(huì)將回調(diào)函數(shù)加入中,等到執(zhí)行。 寫(xiě)在前面 因?yàn)閷?duì)Vue.js很感興趣,而且平時(shí)工作的技術(shù)棧也是Vue.js,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。文章的原地址:https://github.com/ans...

    leo108 評(píng)論0 收藏0
  • Vue.nextTick使用和源碼分析

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

    Jrain 評(píng)論0 收藏0
  • Vue源碼詳解之nextTickMutationObserver只是浮云,microtask才是核

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

    陳偉 評(píng)論0 收藏0

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

0條評(píng)論

閱讀需要支付1元查看
<