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

資訊專欄INFORMATION COLUMN

Vue源碼詳解之nextTick:MutationObserver只是浮云,microtask才是核

陳偉 / 1640人閱讀

摘要:后來(lái)尤雨溪了解到是將回調(diào)放入的隊(duì)列。而且瀏覽器內(nèi)部為了更快的響應(yīng)用戶,內(nèi)部可能是有多個(gè)的而的的優(yōu)先級(jí)可能更高,因此對(duì)于尤雨溪采用的,甚至可能已經(jīng)多次執(zhí)行了的,都沒有執(zhí)行的,也就導(dǎo)致了我們更新操

原發(fā)于我的博客。

前一篇文章已經(jīng)詳細(xì)記述了Vue的核心執(zhí)行過(guò)程。相當(dāng)于已經(jīng)搞定了主線劇情。后續(xù)的文章都會(huì)對(duì)其中沒有介紹的細(xì)節(jié)進(jìn)行展開。

現(xiàn)在我們就來(lái)講講其他支線任務(wù):nextTick和microtask。

Vue的nextTick api的實(shí)現(xiàn)部分是Vue里比較好理解的一部分,與其他部分的代碼也非常的解耦,因此這一塊的相關(guān)源碼解析文章很多。我本來(lái)也不準(zhǔn)備多帶帶寫博客細(xì)說(shuō)這部分,但是最近偶然在別人的文章中了解到:
每輪次的event loop中,每次執(zhí)行一個(gè)task,并執(zhí)行完microtask隊(duì)列中的所有microtask之后,就會(huì)進(jìn)行UI的渲染。但是作者似乎對(duì)于這個(gè)結(jié)論也不是很肯定。而我第一反應(yīng)就是Vue的$nextTick既然用到了MutationObserver(MO的回調(diào)放進(jìn)的是microtask的任務(wù)隊(duì)列中的),那么是不是也是出于這個(gè)考慮呢?于是我想研究了一遍Vue的$nextTick,就可以了解是不是出于這個(gè)目的,也同時(shí)看能不能佐證UI Render真的是在microtask隊(duì)列清空后執(zhí)行的。

研究之后的結(jié)論:我之前對(duì)于$nextTick源碼的理解完全是錯(cuò)的,以及每輪事件循環(huán)執(zhí)行完所有的microtask,是會(huì)執(zhí)行UI Render的。

task/macrotask和microtask的概念自從去年知乎上有人提出這個(gè)問(wèn)題之后,task和microtask已經(jīng)被很多同學(xué)了解了,我也是當(dāng)時(shí)看到了microtask的內(nèi)容,現(xiàn)在已經(jīng)有非常多的中文介紹博客在介紹這部分的知識(shí),最近這篇火遍掘金、SF和知乎的文章,最后也是考了microtask的概念。如果你沒有看過(guò)task/microtask的內(nèi)容的話,我還是推薦這篇英文博客,是絕大多數(shù)國(guó)內(nèi)博客的內(nèi)容來(lái)源。

先說(shuō)nextTick的具體實(shí)現(xiàn)

先用120秒介紹MutationObserver: MO是HTML5中的新API,是個(gè)用來(lái)監(jiān)視DOM變動(dòng)的接口。他能監(jiān)聽一個(gè)DOM對(duì)象上發(fā)生的子節(jié)點(diǎn)刪除、屬性修改、文本內(nèi)容修改等等。
調(diào)用過(guò)程很簡(jiǎn)單,但是有點(diǎn)不太尋常:你需要先給他綁回調(diào):
var mo = new MutationObserver(callback)
通過(guò)給MO的構(gòu)造函數(shù)傳入一個(gè)回調(diào),能得到一個(gè)MO實(shí)例,這個(gè)回調(diào)就會(huì)在MO實(shí)例監(jiān)聽到變動(dòng)時(shí)觸發(fā)。

這個(gè)時(shí)候你只是給MO實(shí)例綁定好了回調(diào),他具體監(jiān)聽哪個(gè)DOM、監(jiān)聽節(jié)點(diǎn)刪除還是監(jiān)聽屬性修改,你都還沒有設(shè)置。而調(diào)用他的observer方法就可以完成這一步:

var domTarget = 你想要監(jiān)聽的dom節(jié)點(diǎn)
mo.observe(domTarget, {
      characterData: true //說(shuō)明監(jiān)聽文本內(nèi)容的修改。
})

一個(gè)需要先說(shuō)的細(xì)節(jié)是,MutationObserver的回調(diào)是放在microtask中執(zhí)行的。

ok了,現(xiàn)在這個(gè)domTarget上發(fā)生的文本內(nèi)容修改就會(huì)被mo監(jiān)聽到,mo就會(huì)觸發(fā)你在new MutationObserver(callback)中傳入的callback。

現(xiàn)在我們來(lái)看Vue.nextTick的源碼:

export const nextTick = (function () {
  var callbacks = []
  var pending = false
  var timerFunc
  function nextTickHandler () {
    pending = false
    // 之所以要slice復(fù)制一份出來(lái)是因?yàn)橛械腸b執(zhí)行過(guò)程中又會(huì)往callbacks中加入內(nèi)容
    // 比如$nextTick的回調(diào)函數(shù)里又有$nextTick
    // 這些是應(yīng)該放入到下一個(gè)輪次的nextTick去執(zhí)行的,
    // 所以拷貝一份當(dāng)前的,遍歷執(zhí)行完當(dāng)前的即可,避免無(wú)休止的執(zhí)行下去
    var copies = callbacks.slice(0)
    callbacks = []
    for (var i = 0; i < copies.length; i++) {
      copies[i]()
    }
  }

  /* istanbul ignore if */
  // ios9.3以上的WebView的MutationObserver有bug,
  //所以在hasMutationObserverBug中存放了是否是這種情況
  if (typeof MutationObserver !== "undefined" && !hasMutationObserverBug) {
    var counter = 1
    // 創(chuàng)建一個(gè)MutationObserver,observer監(jiān)聽到dom改動(dòng)之后后執(zhí)行回調(diào)nextTickHandler
    var observer = new MutationObserver(nextTickHandler)
    var textNode = document.createTextNode(counter)
    // 調(diào)用MutationObserver的接口,觀測(cè)文本節(jié)點(diǎn)的字符內(nèi)容
    observer.observe(textNode, {
      characterData: true
    })
    // 每次執(zhí)行timerFunc都會(huì)讓文本節(jié)點(diǎn)的內(nèi)容在0/1之間切換,
    // 不用true/false可能是有的瀏覽器對(duì)于文本節(jié)點(diǎn)設(shè)置內(nèi)容為true/false有bug?
    // 切換之后將新值賦值到那個(gè)我們MutationObserver觀測(cè)的文本節(jié)點(diǎn)上去
    timerFunc = function () {
      counter = (counter + 1) % 2
      textNode.data = counter
    }
  } else {
    // webpack attempts to inject a shim for setImmediate
    // if it is used as a global, so we have to work around that to
    // avoid bundling unnecessary code.
    // webpack默認(rèn)會(huì)在代碼中插入setImmediate的墊片
    // 沒有MutationObserver就優(yōu)先用setImmediate,不行再用setTimeout
    const context = inBrowser
      ? window
      : typeof global !== "undefined" ? global : {}
    timerFunc = context.setImmediate || setTimeout
  }
  return function (cb, ctx) {
    var func = ctx
      ? function () { cb.call(ctx) }
      : cb
    callbacks.push(func)
    // 如果pending為true, 就其實(shí)表明本輪事件循環(huán)中已經(jīng)執(zhí)行過(guò)timerFunc(nextTickHandler, 0)
    if (pending) return
    pending = true
    timerFunc(nextTickHandler, 0)
  }
})()

上面這個(gè)函數(shù)執(zhí)行過(guò)程后生成的那個(gè)函數(shù)才是nextTick。而這個(gè)函數(shù)的執(zhí)行過(guò)程就是先初始化pending變量和cb變量,cb用來(lái)存放需要執(zhí)行的回調(diào),pending表示是否把清空回調(diào)的nextTickHandler函數(shù)加入到異步隊(duì)列中。

然后就是創(chuàng)建了一個(gè)MO,這個(gè)MO監(jiān)聽了一個(gè)新創(chuàng)建的文本節(jié)點(diǎn)的文本內(nèi)容變化,同時(shí)監(jiān)聽到變化時(shí)的回調(diào)就是nextTickHandler。nextTickHandler遍歷cb數(shù)組,把需要執(zhí)行的cb給拿出來(lái)一個(gè)個(gè)執(zhí)行了。

而最后返回出去作為nextTick的那個(gè)函數(shù)就比較簡(jiǎn)單了:

function (cb, ctx) {
    var func = ctx
      ? function () { cb.call(ctx) }
      : cb
    callbacks.push(func)
    // 如果pending為true, 就其實(shí)表明本輪事件循環(huán)中已經(jīng)執(zhí)行過(guò)timerFunc(nextTickHandler, 0)
    if (pending) return
    pending = true
    timerFunc(nextTickHandler, 0)
  }
}

也就是把傳入的回調(diào)放入cb數(shù)組當(dāng)中,然后執(zhí)行timerFunc(nextTickHandler, 0),其實(shí)是執(zhí)行timerFunc(),后面?zhèn)魅氲膬蓞?shù)沒用,在瀏覽器不支持MO的情況timerFunc才回退到setTimeout,那倆參數(shù)才有效果。timerFunc就是把那個(gè)被MO監(jiān)聽的文本節(jié)點(diǎn)改一下它的內(nèi)容,這樣我改了文本內(nèi)容,MO就會(huì)在當(dāng)前的所有同步代碼完成之后執(zhí)行回調(diào),從而執(zhí)行數(shù)據(jù)更新到DOM上之后的任務(wù)。

我一開始在看這一段代碼時(shí)忘記了MutationObserver的回調(diào)是在microtask里執(zhí)行的。而且當(dāng)時(shí)也還沒有看過(guò)Vue的其他源碼,當(dāng)時(shí)的我大體看懂nextTick代碼流程之后,形成了如下的理解,而且覺得似乎完美的解釋了代碼邏輯:
watcher監(jiān)聽到數(shù)據(jù)變化之后,會(huì)立馬去修改dom,接著用戶書寫的代碼里的nextTick被執(zhí)行,而nextTick內(nèi)部也是去修改DOM(textNode),當(dāng)這個(gè)最后修改的textNode修改完成了,觸發(fā)了MutationObserver的回調(diào),那就意味著,前面的DOM修改也已經(jīng)完成了,所以nextTick向用戶保證的DOM更新之后再執(zhí)行用戶的回調(diào)就得以實(shí)現(xiàn)了。

Damn,現(xiàn)在看了Batcher的代碼和認(rèn)真反思了以后,立馬醒悟,上面的想法完完全全就是一坨狗屎,totally shit!

首先,一個(gè)普遍的常識(shí)是DOM Tree的修改是實(shí)時(shí)的,而修改的Render到DOM上才是異步的。根本不存在什么所謂的等待DOM修改完成,任何時(shí)候我在上一行代碼里往DOM中添加了一個(gè)元素、修改了一個(gè)DOM的textContent,你在下一行代碼里一定能立馬就讀取到新的DOM,我知道這個(gè)理。但是我還是搞不懂我怎么會(huì)產(chǎn)生用nextTick來(lái)保證DOM修改的完成這樣的怪念頭。可能那天屎吃得有點(diǎn)多了。

其次,我們來(lái)看看使用nextTick的真正原因:

Vue在兩個(gè)地方用到了上述nextTick:

Vue.nextTick和Vue.prototype.$nextTick都是直接使用了這個(gè)nextTick

在batcher中,也就是watcher觀測(cè)到數(shù)據(jù)變化后執(zhí)行的是nextTick(flushBatcherQueue)flushBatcherQueue則負(fù)責(zé)執(zhí)行完成所有的dom更新操作。

Batcher的源碼,我在上一篇文章當(dāng)中已經(jīng)詳細(xì)的分析了,在這里我用一張圖來(lái)說(shuō)明它和nextTick的詳細(xì)處理過(guò)程吧。
假設(shè)此時(shí)Vue實(shí)例的模板為:

{{a}}

仔細(xì)跟蹤了代碼執(zhí)行過(guò)程我們會(huì)發(fā)現(xiàn),真正的去遍歷watcher,批處理更新是在microtask中執(zhí)行的,而且用戶在修改數(shù)據(jù)后自己執(zhí)行的nextTick(cb)也會(huì)在此時(shí)執(zhí)行cb,他們都是在同一個(gè)microtask中執(zhí)行。根本就不是我最開始想的那樣,把回調(diào)放在以后的事件循環(huán)中去執(zhí)行。

同時(shí),上面這個(gè)過(guò)程也深切的揭露出Vue nextTick的本質(zhì),我不是想要MO來(lái)幫我真正監(jiān)聽DOM更改,我只是想要一個(gè)異步API,用來(lái)在當(dāng)前的同步代碼執(zhí)行完畢后,執(zhí)行我想執(zhí)行的異步回調(diào)。

之所以要這樣,是因?yàn)橛脩舻拇a當(dāng)中是可能多次修改數(shù)據(jù)的,而每次修改都會(huì)同步通知到所有訂閱該數(shù)據(jù)的watcher,而立馬執(zhí)行將數(shù)據(jù)寫到DOM上是肯定不行的,那就只是把watcher加入數(shù)組。等到當(dāng)前task執(zhí)行完畢,所有的同步代碼已經(jīng)完成,那么這一輪次的數(shù)據(jù)修改就已經(jīng)結(jié)束了,這個(gè)時(shí)候我可以安安心心的去將對(duì)監(jiān)聽到依賴變動(dòng)的watcher完成數(shù)據(jù)真正寫入到DOM上的操作,這樣即使你在之前的task里改了一個(gè)watcher的依賴100次,我最終只會(huì)計(jì)算一次value、改DOM一次。一方面省去了不必要的DOM修改,另一方面將DOM操作聚集,可以提升DOM Render效率。

那為什么一定要用MutationObserver呢?不,并沒有一定要用MO,只要是microtask都可以。在最新版的Vue源碼里,優(yōu)先使用的就是Promise.resolve().then(nextTickHandler)來(lái)將異步回調(diào)放入到microtask中(MO在IOS9.3以上的WebView中有bug),沒有原生Promise才用MO。

這充分說(shuō)明了microtask才是nextTick的本質(zhì),MO什么的只是個(gè)備胎,要是有比MO優(yōu)先級(jí)更高、瀏覽器兼容性更好的microtask,那可能就分分鐘把MO拿下了。

那問(wèn)題又來(lái)了,為什么一定要microtask?task可以嗎?(macrotask和task是一回事哈,HTML5標(biāo)準(zhǔn)里甚至都沒有macrotask這個(gè)詞)。

哈,現(xiàn)在剛好有個(gè)例子,Vue一開始曾經(jīng)改過(guò)nextTick的實(shí)現(xiàn)。我們來(lái)看看這兩個(gè)jsFiddle:jsfiddle1和jsfiddle2。

兩個(gè)fiddle的實(shí)現(xiàn)一模一樣,就是讓那個(gè)絕對(duì)定位的黃色元素起到一個(gè)fixed定位的效果:綁定scroll事件,每次滾動(dòng)的時(shí)候,計(jì)算當(dāng)前滾動(dòng)的位置并更改到那個(gè)絕對(duì)定位元素的top屬性上去。大家自己試試滾動(dòng)幾下,對(duì)比下效果,你就會(huì)發(fā)現(xiàn)第一個(gè)fiddle中的黃元素是穩(wěn)定不動(dòng)的,fixed很好。而后一個(gè)fiddle中就有問(wèn)題了,黃色元素上下晃動(dòng),似乎跟不上我們scroll的節(jié)奏,總要慢一點(diǎn),雖然最后停下滾動(dòng)時(shí)位置是對(duì)的。

上述兩個(gè)例子其實(shí)是在這個(gè)issue中找到的,第一個(gè)jsfiddle使用的版本是Vue 2.0.0-rc.6,這個(gè)版本的nextTick實(shí)現(xiàn)是采用了MO,而后因?yàn)镮OS9.3的WebView里的MO有bug,于是尤雨溪更改了實(shí)現(xiàn),換成了window.postMessage,也就是后一個(gè)fiddle所使用的Vue 2.0.0-rc.7。后來(lái)尤雨溪了解到window.postMessage是將回調(diào)放入的macrotask 隊(duì)列。這就是問(wèn)題的根源了。

HTML中的UI事件、網(wǎng)絡(luò)事件、HTML Parsing等都是使用的task來(lái)完成,因此每次scroll事件觸發(fā)后,在當(dāng)前的task里只是完成了把watcher加入隊(duì)列和把清空watcher的flushBatcherQueue作為異步回調(diào)傳入nextTick。

如果nextTick使用的是microtask,那么在task執(zhí)行完畢之后就會(huì)立即執(zhí)行所有microtask,那么flushBatcherQueue(真正修改DOM)便得以在此時(shí)立即完成,而后,當(dāng)前輪次的microtask全部清理完成時(shí),執(zhí)行UI rendering,把重排重繪等操作真正更新到DOM上(后文會(huì)細(xì)說(shuō))。(注意,頁(yè)面的滾動(dòng)效果并不需要重繪哈。重繪是當(dāng)你修改了UI樣式、DOM結(jié)構(gòu)等等,頁(yè)面將樣式呈現(xiàn)出來(lái),別暈了。)
如果nextTick使用的是task,那么會(huì)在當(dāng)前的task和所有microtask執(zhí)行完畢之后才在以后的某一次task執(zhí)行過(guò)程中處理flushBatcherQueue,那個(gè)時(shí)候才真正執(zhí)行各個(gè)指令的修改DOM操作,但那時(shí)為時(shí)已晚,錯(cuò)過(guò)了多次觸發(fā)重繪、渲染UI的時(shí)機(jī)。而且瀏覽器內(nèi)部為了更快的響應(yīng)用戶UI,內(nèi)部可能是有多個(gè)task queue的:

For example, a user agent could have one task queue for mouse and key events (the user interaction task source), and another for everything else. The user agent could then give keyboard and mouse events preference over other tasks three quarters of the time, keeping the interface responsive but not starving other task queues, and never processing events from any one task source out of order.

而UI的task queue的優(yōu)先級(jí)可能更高,因此對(duì)于尤雨溪采用的window.postMessage,甚至可能已經(jīng)多次執(zhí)行了UI的task,都沒有執(zhí)行window.postMessage的task,也就導(dǎo)致了我們更新DOM操作的延遲。在重CPU計(jì)算、UI渲染任務(wù)情況下,這一延遲達(dá)到issue觀測(cè)到的100毫秒到1秒的級(jí)別是完全課可能的。因此,使用task來(lái)實(shí)現(xiàn)nextTick是不可行的,而尤雨溪也撤回了這一次的修改,后續(xù)的nextTick實(shí)現(xiàn)中,依然是使用的Promise.then和MO。

task microtask和每輪event loop之后的UI Render

我最近認(rèn)真閱讀了一下HTML5規(guī)范,還是來(lái)說(shuō)一說(shuō)task和microtask處理完成之后的UI渲染過(guò)程,講一下每次task執(zhí)行和所有microtask執(zhí)行完畢后使如何完成UI Render的。

先上HTML標(biāo)準(zhǔn)原文:
比較典型的task有如下這些

Events
Dispatching an Event object at a particular EventTarget object is often done by a dedicated task. Not all events are dispatched using the task queue, many are dispatched during other tasks.

Parsing
The HTML parser tokenizing one or more bytes, and then processing any resulting tokens, is typically a task.

Callbacks
Calling a callback is often done by a dedicated task.

Using a resource
When an algorithm fetches a resource, if the fetching occurs in a non-blocking fashion then the processing of the resource once some or all of the resource is available is performed by a task.

Reacting to DOM manipulation
Some elements have tasks that trigger in response to DOM manipulation, e.g. when that element is inserted into the document.

此外,還包括setTimeout, setInterval, setImmediate, window.postMessage等等。
上述Reacting to DOM manipulation并不是說(shuō)你執(zhí)行DOM操作時(shí)就會(huì)把這個(gè)DOM操作的執(zhí)行當(dāng)成一個(gè)task。是那些異步的reacting會(huì)被當(dāng)做task。

HTML5標(biāo)準(zhǔn):task、microtask和UI render的具體執(zhí)行過(guò)程如下:

An event loop must continually run through the following steps for as long as it exists:

1.Select the oldest task on one of the event loop"s task queues, if any, ignoring, in the case of a browsing context event loop, tasks whose associated Documents are not fully active. The user agent may pick any task queue. If there is no task to select, then jump to the microtasks step below.

2.Set the event loop"s currently running task to the task selected in the previous step.

3.Run: Run the selected task.

4.Set the event loop"s currently running task back to null.

5.Remove the task that was run in the run step above from its task queue.

6.Microtasks: Perform a microtask checkpoint. //這里會(huì)執(zhí)行所有的microtask

7.Update the rendering: If this event loop is a browsing context event loop (as opposed to a worker event loop), then run the following substeps.

7.1 Let now be the value that would be returned by the Performance object"s now() method.
7.2 Let docs be the list of Document objects associated with the event loop in question, sorted arbitrarily except that the following conditions must be met:
7.3 If there are top-level browsing contexts B that the user agent believes would not benefit from having their rendering updated at this time, then remove from docs all Document objects whose browsing context"s top-level browsing context is in B.
7.4 If there are a nested browsing contexts B that the user agent believes would not benefit from having their rendering updated at this time, then remove from docs all Document objects whose browsing context is in B.
7.5 For each fully active Document in docs, run the resize steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
7.6 For each fully active Document in docs, run the scroll steps for that Document, passing in now as the timestamp. [CSSOMVIEW]
7.7 For each fully active Document in docs, evaluate media queries and report changes for that Document, passing in now as the timestamp. [CSSOMVIEW]
7.8 For each fully active Document in docs, run CSS animations and send events for that Document, passing in now as the timestamp. [CSSANIMATIONS]
7.9 For each fully active Document in docs, run the fullscreen rendering steps for that Document, passing in now as the timestamp. [FULLSCREEN]
7.10 For each fully active Document in docs, run the animation frame callbacks for that Document, passing in now as the timestamp.
7.11 For each fully active Document in docs, run the update intersection observations steps for that Document, passing in now as the timestamp. [INTERSECTIONOBSERVER]
7.12 For each fully active Document in docs, update the rendering or user interface of that Document and its browsing context to reflect the current state.

8.If this is a worker event loop (i.e. one running for a WorkerGlobalScope), but there are no tasks in the event loop"s task queues and the WorkerGlobalScope object"s closing flag is true, then destroy the event loop, aborting these steps, resuming the run a worker steps described in the Web workers section below.
9.Return to the first step of the event loop.

解釋一下:第一步,從多個(gè)task queue中的一個(gè)queue里,挑出一個(gè)最老的task。(因?yàn)橛卸鄠€(gè)task queue的存在,使得瀏覽器可以完成我們前面說(shuō)的,優(yōu)先、高頻率的執(zhí)行某些task queue中的任務(wù),比如UI的task queue)。
然后2到5步,執(zhí)行這個(gè)task。
第六步, Perform a microtask checkpoint. ,這里會(huì)執(zhí)行完microtask queue中的所有的microtask,如果microtask執(zhí)行過(guò)程中又添加了microtask,那么仍然會(huì)執(zhí)行新添加的microtask,當(dāng)然,這個(gè)機(jī)制好像有限制,一輪microtask的執(zhí)行總量似乎有限制(1000?),數(shù)量太多就執(zhí)行一部分留下的以后再執(zhí)行?這里我不太確定。

第七步,Update the rendering:
7.2到7.4,當(dāng)前輪次的event loop中關(guān)聯(lián)到的document對(duì)象會(huì)保持某些特定順序,這些document對(duì)象都會(huì)執(zhí)行需要執(zhí)行UI render的,但是并不是所有關(guān)聯(lián)到的document都需要更新UI,瀏覽器會(huì)判斷這個(gè)document是否會(huì)從UI Render中獲益,因?yàn)闉g覽器只需要保持60Hz的刷新率即可,而每輪event loop都是非常快的,所以沒必要每個(gè)document都Render UI。
7.5和7.6 run the resize steps/run the scroll steps不是說(shuō)去執(zhí)行resize和scroll。每次我們scoll的時(shí)候視口或者dom就已經(jīng)立即scroll了,并把document或者dom加入到 pending scroll event targets中,而run the scroll steps具體做的則是遍歷這些target,在target上觸發(fā)scroll事件。run the resize steps也是相似的,這個(gè)步驟是觸發(fā)resize事件。
7.8和7.9 后續(xù)的media query, run CSS animations and send events等等也是相似的,都是觸發(fā)事件,第10步和第11步則是執(zhí)行我們熟悉的requestAnimationFrame回調(diào)和IntersectionObserver回調(diào)(第十步還是挺關(guān)鍵的,raf就是在這執(zhí)行的!)。
7.12 渲染UI,關(guān)鍵就在這了。

第九步 繼續(xù)執(zhí)行event loop,又去執(zhí)行task,microtasks和UI render。

更新:找到一張圖,不過(guò)著重說(shuō)明的是整個(gè)event loop,沒有細(xì)說(shuō)UI render。

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

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

相關(guān)文章

  • event loop 與 vue

    摘要:但是導(dǎo)致了很明顯的性能問(wèn)題。上述兩個(gè)例子其實(shí)是在這個(gè)中找到的,第一個(gè)使用的版本是,這個(gè)版本的實(shí)現(xiàn)是采用了,而后因?yàn)榈睦锏挠校谑怯扔晗牧藢?shí)現(xiàn),換成了,也就是后一個(gè)所使用的。后來(lái)尤雨溪了解到是將回調(diào)放入的隊(duì)列。 結(jié)論 對(duì)于event loop 可以抽象成一段簡(jiǎn)單的代碼表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...

    springDevBird 評(píng)論0 收藏0
  • event loop 與 vue

    摘要:但是導(dǎo)致了很明顯的性能問(wèn)題。上述兩個(gè)例子其實(shí)是在這個(gè)中找到的,第一個(gè)使用的版本是,這個(gè)版本的實(shí)現(xiàn)是采用了,而后因?yàn)榈睦锏挠校谑怯扔晗牧藢?shí)現(xiàn),換成了,也就是后一個(gè)所使用的。后來(lái)尤雨溪了解到是將回調(diào)放入的隊(duì)列。 結(jié)論 對(duì)于event loop 可以抽象成一段簡(jiǎn)單的代碼表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...

    Barry_Ng 評(píng)論0 收藏0
  • Vue源碼Vue中DOM的異步更新策略以及nextTick機(jī)制

    摘要:本篇文章主要是對(duì)中的異步更新策略和機(jī)制的解析,需要讀者有一定的使用經(jīng)驗(yàn)并且熟悉掌握事件循環(huán)模型。這個(gè)結(jié)果足以說(shuō)明中的更新并非同步。二是把回調(diào)函數(shù)放入一個(gè)隊(duì)列,等待適當(dāng)?shù)臅r(shí)機(jī)執(zhí)行。通過(guò)的主動(dòng)來(lái)觸發(fā)的事件,進(jìn)而把回調(diào)函數(shù)作為參與事件循環(huán)。 本篇文章主要是對(duì)Vue中的DOM異步更新策略和nextTick機(jī)制的解析,需要讀者有一定的Vue使用經(jīng)驗(yàn)并且熟悉掌握J(rèn)avaScript事件循環(huán)模型。 ...

    selfimpr 評(píng)論0 收藏0
  • 淺析 Vue 2.6 中的 nextTick 方法

    摘要:核心的異步延遲函數(shù),用于異步延遲調(diào)用函數(shù)優(yōu)先使用原生原本支持更廣,但在的中,觸摸事件處理程序中觸發(fā)會(huì)產(chǎn)生嚴(yán)重錯(cuò)誤的,回調(diào)被推入隊(duì)列但是隊(duì)列可能不會(huì)如期執(zhí)行。 淺析 Vue 2.6 中的 nextTick 方法。 事件循環(huán) JS 的 事件循環(huán) 和 任務(wù)隊(duì)列 其實(shí)是理解 nextTick 概念的關(guān)鍵。這個(gè)網(wǎng)上其實(shí)有很多優(yōu)質(zhì)的文章做了詳細(xì)介紹,我就簡(jiǎn)單過(guò)過(guò)了。 以下內(nèi)容適用于瀏覽器端 JS,...

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

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

0條評(píng)論

閱讀需要支付1元查看
<