成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

寫一個JavaScript框架:比setTimeout更棒的定時執(zhí)行

移動開發(fā)
這是 JavaScript 框架系列的第二章。在這一章里,我打算講一下在瀏覽器里的異步代碼不同執(zhí)行方式。你將了解定時器和事件循環(huán)之間的不同差異,比如 setTimeout 和 Promises。這個系列是關(guān)于一個開源的客戶端框架,叫做 NX。在這個系列里,我主要解釋一下寫該框架不得不克服的主要困難。

[[177395]]

這是 JavaScript 框架系列的第二章。在這一章里,我打算講一下在瀏覽器里的異步代碼不同執(zhí)行方式。你將了解定時器和事件循環(huán)之間的不同差異,比如 setTimeout 和 Promises。

這個系列是關(guān)于一個開源的客戶端框架,叫做 NX。在這個系列里,我主要解釋一下寫該框架不得不克服的主要困難。如果你對 NX 感興趣可以參觀我們的 主頁

這個系列包含以下幾個章節(jié):

  1. 項目結(jié)構(gòu)
  2. 定時執(zhí)行 (當(dāng)前章節(jié))
  3. 沙箱代碼評估
  4. 數(shù)據(jù)綁定介紹
  5. 數(shù)據(jù)綁定與 ES6 代理
  6. 自定義元素
  7. 客戶端路由

異步代碼執(zhí)行

你可能比較熟悉 Promise、process.nextTick()、setTimeout(),或許還有 requestAnimationFrame() 這些異步執(zhí)行代碼的方式。它們內(nèi)部都使用了事件循環(huán),但是它們在精確計時方面有一些不同。

在這一章里,我將解釋它們之間的不同,然后給大家演示怎樣在一個類似 NX 這樣的先進(jìn)框架里面實現(xiàn)一個定時系統(tǒng)。不用我們重新做一個,我們將使用原生的事件循環(huán)來達(dá)到我們的目的。

事件循環(huán)

事件循環(huán)甚至沒有在 ES6 規(guī)范里提到。JavaScript 自身只有任務(wù)(Job)和任務(wù)隊列(job queue)。更加復(fù)雜的事件循環(huán)是在 NodeJS 和 HTML5 規(guī)范里分別定義的,因為這篇是針對前端的,我會在詳細(xì)說明后者。

事件循環(huán)可以被看做某個條件的循環(huán)。它不停的尋找新的任務(wù)來運行。這個循環(huán)中的一次迭代叫做一個滴答(tick)。在一次滴答期間執(zhí)行的代碼稱為一次任務(wù)(task)。

  1. while (eventLoop.waitForTask()) {   
  2.   eventLoop.processNextTask() 

任務(wù)是同步代碼,它可以在循環(huán)中調(diào)度其它任務(wù)。一個簡單的調(diào)用新任務(wù)的方式是 setTimeout(taskFn)。不管怎樣, 任務(wù)可能有很多來源,比如用戶事件、網(wǎng)絡(luò)或者 DOM 操作。

 [[177396]]

 

任務(wù)隊列

更復(fù)雜一些的是,事件循環(huán)可以有多個任務(wù)隊列。這里有兩個約束條件,相同任務(wù)源的事件必須在相同的隊列,以及任務(wù)必須按插入的順序進(jìn)行處理。除此之外,瀏覽器可以做任何它想做的事情。例如,它可以決定接下來處理哪個任務(wù)隊列。

  1. while (eventLoop.waitForTask()) {   
  2.   const taskQueue = eventLoop.selectTaskQueue() 
  3.   if (taskQueue.hasNextTask()) { 
  4.     taskQueue.processNextTask() 
  5.   } 

用這個模型,我們不能精確的控制定時。如果用 setTimeout()瀏覽器可能決定先運行完其它幾個隊列才運行我們的隊列。

 

[[177397]]

 

微任務(wù)隊列

幸運的是,事件循環(huán)還提供了一個叫做微任務(wù)(microtask)隊列的單一隊列。當(dāng)前任務(wù)結(jié)束的時候,微任務(wù)隊列會清空每個滴答里的任務(wù)。

  1. while (eventLoop.waitForTask()) {   
  2.   const taskQueue = eventLoop.selectTaskQueue() 
  3.   if (taskQueue.hasNextTask()) { 
  4.     taskQueue.processNextTask() 
  5.   } 
  6.   const microtaskQueue = eventLoop.microTaskQueue 
  7.   while (microtaskQueue.hasNextMicrotask()) { 
  8.     microtaskQueue.processNextMicrotask() 
  9.   } 

最簡單的調(diào)用微任務(wù)的方法是 Promise.resolve().then(microtaskFn)。微任務(wù)按照插入順序進(jìn)行處理,并且由于僅存在一個微任務(wù)隊列,瀏覽器不會把時間弄亂了。

此外,微任務(wù)可以調(diào)度新的微任務(wù),它將插入到同一個隊列,并在同一個滴答內(nèi)處理。

 

[[177398]]

 

繪制Rendering

***是繪制Rendering調(diào)度,不同于事件處理和分解,繪制并不是在單獨的后臺任務(wù)完成的。它是一個可以運行在每個循環(huán)滴答結(jié)束時的算法。

在這里瀏覽器又有了許多自由:它可能在每個任務(wù)以后繪制,但是它也可能在好幾百個任務(wù)都執(zhí)行了以后也不繪制。

幸運的是,我們有 requestAnimationFrame(),它在下一個繪制之前執(zhí)行傳遞的函數(shù)。我們最終的事件模型像這樣:

  1. while (eventLoop.waitForTask()) {   
  2.   const taskQueue = eventLoop.selectTaskQueue() 
  3.   if (taskQueue.hasNextTask()) { 
  4.     taskQueue.processNextTask() 
  5.   } 
  6.   const microtaskQueue = eventLoop.microTaskQueue 
  7.   while (microtaskQueue.hasNextMicrotask()) { 
  8.     microtaskQueue.processNextMicrotask() 
  9.   } 
  10.   if (shouldRender()) { 
  11.     applyScrollResizeAndCSS() 
  12.     runAnimationFrames() 
  13.     render() 
  14.   } 

現(xiàn)在用我們所知道知識來創(chuàng)建定時系統(tǒng)!

利用事件循環(huán)

和大多數(shù)現(xiàn)代框架一樣,NX 也是基于 DOM 操作和數(shù)據(jù)綁定的。批量操作和異步執(zhí)行以取得更好的性能表現(xiàn)?;谝陨侠碛晌覀冇?Promises、 MutationObservers 和 requestAnimationFrame()。

我們所期望的定時器是這樣的:

  1. 代碼來自于開發(fā)者
  2. 數(shù)據(jù)綁定和 DOM 操作由 NX 來執(zhí)行
  3. 開發(fā)者定義事件鉤子
  4. 瀏覽器進(jìn)行繪制

步驟 1

NX 寄存器對象基于 ES6 代理 以及 DOM 變動基于MutationObserver (變動觀測器)同步運行(下一節(jié)詳細(xì)介紹)。 它作為一個微任務(wù)延遲直到步驟 2 執(zhí)行以后才做出反應(yīng)。這個延遲已經(jīng)在Promise.resolve().then(reaction) 進(jìn)行了對象轉(zhuǎn)換,并且它將通過變動觀測器自動運行。

步驟 2

來自開發(fā)者的代碼(任務(wù))運行完成。微任務(wù)由 NX 開始執(zhí)行所注冊。 因為它們是微任務(wù),所以按序執(zhí)行。注意,我們?nèi)匀辉谕粋€滴答循環(huán)中。

步驟 3

開發(fā)者通過 requestAnimationFrame(hook) 通知 NX 運行鉤子。這可能在滴答循環(huán)后發(fā)生。重要的是,鉤子運行在下一次繪制之前和所有數(shù)據(jù)操作之后,并且 DOM 和 CSS 改變都已經(jīng)完成。

步驟 4

瀏覽器繪制下一個視圖。這也有可能發(fā)生在滴答循環(huán)之后,但是絕對不會發(fā)生在一個滴答的步驟 3 之前。

牢記在心里的事情

我們在原生的事件循環(huán)之上實現(xiàn)了一個簡單而有效的定時系統(tǒng)。理論上講它運行的很好,但是還是很脆弱,一個輕微的錯誤可能會導(dǎo)致很嚴(yán)重的 BUG。

在一個復(fù)雜的系統(tǒng)當(dāng)中,最重要的就是建立一定的規(guī)則并在以后保持它們。在 NX 中有以下規(guī)則:

  1. 永遠(yuǎn)不用 setTimeout(fn, 0) 來進(jìn)行內(nèi)部操作
  2. 用相同的方法來注冊微任務(wù)
  3. 微任務(wù)僅供內(nèi)部操作
  4. 不要干預(yù)開發(fā)者鉤子運行時間

規(guī)則 1 和 2

數(shù)據(jù)反射和 DOM 操作將按照操作順序執(zhí)行。這樣只要不混合就可以很好的延遲它們的執(zhí)行?;旌蠄?zhí)行會出現(xiàn)莫名其妙的問題。

setTimeout(fn, 0) 的行為完全不可預(yù)測。使用不同的方法注冊微任務(wù)也會發(fā)生混亂。例如,下面的例子中 microtask2 不會正確地在 microtask1 之前運行。

  1. Promise.resolve().then().then(microtask1)   
  2. Promise.resolve().then(microtask2)  [[177399]]

規(guī)則 3 和 4

分離開發(fā)者的代碼執(zhí)行和內(nèi)部操作的時間窗口是非常重要的。混合這兩種行為會導(dǎo)致不可預(yù)測的事情發(fā)生,并且它會需要開發(fā)者了解框架內(nèi)部。我想很多前臺開發(fā)者已經(jīng)有過類似經(jīng)歷。

結(jié)論

如果你對 NX 框架感興趣,可以參觀我們的主頁。還可以在 GIT 上找到我們的源代碼。

在下一節(jié)我們再見,我們將討論 沙盒化代碼執(zhí)行!

你也可以給我們留言。

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2012-01-04 13:55:23

Canvas

2020-02-25 20:55:20

JavaScript開發(fā) 技巧

2014-02-14 09:37:01

JavascriptDOM

2017-03-06 14:08:38

JavaScript單線程setTimeout

2017-06-08 15:53:38

PythonWeb框架

2022-02-10 07:41:02

JavaScriponce函數(shù)

2023-03-01 10:19:23

2021-05-06 10:52:09

Java Spring Bo框架

2021-02-20 09:45:02

RPC框架Java

2013-01-14 09:44:58

JavaScriptJSJS框架

2015-08-24 10:13:48

javascript圖表庫

2015-06-19 11:08:05

JavaScript圖表庫

2011-04-25 08:53:47

JavaScript框架

2015-06-29 11:30:07

JavaScript小烏龜推箱子

2016-12-20 13:55:52

2014-08-19 09:39:46

程序員

2024-01-15 00:35:23

JavaScript框架HTML

2022-09-01 11:48:45

JavaScript框架

2020-10-16 08:26:07

JavaScript開發(fā)技術(shù)

2021-01-13 10:51:08

PromissetTimeout(函數(shù)
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品美女www爽爽爽视频 | 亚洲精品电影网在线观看 | 一区视频在线 | 国产激情在线 | 中文天堂在线观看 | 五月婷婷丁香 | 欧美一级二级三级 | 91国内精精品久久久久久婷婷 | 久久小视频 | 久久久久久国产精品久久 | 99tv| 精品成人在线视频 | 久久久久一区二区三区 | 久久丝袜 | 国产一区二区 | 成人av资源在线 | 久久一区二区免费视频 | 国产精品国产亚洲精品看不卡15 | 久久精品久久综合 | 亚洲视频在线免费观看 | 欧美日韩一区不卡 | 精品视频 免费 | 北条麻妃99精品青青久久主播 | 精品美女 | 性欧美xxxx| 中文字幕视频在线 | 国产精品久久一区 | 超碰97人人人人人蜜桃 | 欧美一区在线视频 | 亚洲欧洲日本国产 | 国产精选一区 | 国精产品一区一区三区免费完 | 国产精品日韩在线 | a级免费黄色片 | 久久久精 | 亚洲欧美在线免费观看 | 国产激情综合五月久久 | 97超碰免费 | 五月婷婷丁香 | 色嗨嗨 | 亚洲欧美日韩在线一区二区 |