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

資訊專欄INFORMATION COLUMN

初窺JavaScript事件機(jī)制的實(shí)現(xiàn)(二)—— Node.js中定時器的實(shí)現(xiàn)

novo / 3247人閱讀

摘要:下面通過幾個的定時器示例以及相關(guān)源碼來分析在中,功能到底是怎么實(shí)現(xiàn)的。我們知道,中的定時器并不同于計(jì)算機(jī)底層的定時中斷。補(bǔ)充資料在高級程序設(shè)計(jì)第三版第章高級技巧中對高級定時器以及有較詳細(xì)的討論。至此,這類定時器函數(shù)已經(jīng)可以為所用了。

上一篇博文提到,在Node中timer并不是通過新開線程來實(shí)現(xiàn)的,而是直接在event loop中完成。下面通過幾個JavaScript的定時器示例以及Node相關(guān)源碼來分析在Node中,timer功能到底是怎么實(shí)現(xiàn)的。

JavaScript中定時器功能的特點(diǎn)

無論是Node還是瀏覽器中,都有setTimeout和setInterval這兩個定時器函數(shù),并且其工作特點(diǎn)基本相同,因此下面僅以Node為例進(jìn)行分析。

我們知道,JavaScript中的定時器并不同于計(jì)算機(jī)底層的定時中斷。中斷到來時,當(dāng)前執(zhí)行代碼會被打斷,轉(zhuǎn)去執(zhí)行定時中斷處理函數(shù)。而JavaScript的定時器到時,如果當(dāng)前執(zhí)行線程沒有正在執(zhí)行的代碼,則執(zhí)行相應(yīng)的回調(diào)函數(shù);如果當(dāng)前有代碼在執(zhí)行中,JavaScript引擎既不會中斷當(dāng)前代碼轉(zhuǎn)去執(zhí)行回調(diào),也不會開新的線程執(zhí)行回調(diào),而是當(dāng)前代碼執(zhí)行完畢之后才去處理。

console.time("A")
setTimeout(function () {
    console.timeEnd("A");
}, 100);
var i = 0;
for (; i < 100000; i++) { }

執(zhí)行上面的代碼,可以看到最終輸出的時間并不是100ms左右,而是數(shù)秒。這說明在循環(huán)完成之前,定時回調(diào)函數(shù)確實(shí)沒有被執(zhí)行,而是推遲到了循環(huán)結(jié)束。實(shí)際上在JavaScript代碼執(zhí)行中,所有的事件都無法得到處理,必須等到當(dāng)前代碼全部完成,才能去處理新的事件。這就是為什么在瀏覽器中運(yùn)行耗時JavaScript代碼時,瀏覽器會失去響應(yīng)。為了應(yīng)對這種情況,我們可以采取Yielding Processes的技巧,將耗時的代碼分成小塊(chunks),每處理完一塊就執(zhí)行一次setTimeout,約定在一小段時間后才處理下一塊,而在這段空閑時間里,瀏覽器/Node可以去處理排隊(duì)中的事件。

補(bǔ)充資料

JavaScript 高級程序設(shè)計(jì) 第三版第22章高級技巧中對高級定時器以及Yielding Processes有較詳細(xì)的討論。

Node中的timer實(shí)現(xiàn) libuv對uv_loop_t類型的初始化

上一篇博文提到Node會調(diào)用libuv的uv_run函數(shù)啟動default_loop_ptr進(jìn)行事件調(diào)度,default_loop_ptr指向一個uv_loop_t類型的變量default_loop_struct。Node啟動時會調(diào)用uv_loop_init(&default_loop_struct)對其進(jìn)行初始化,uv_loop_init函數(shù)節(jié)選如下:

int uv_loop_init(uv_loop_t* loop) {
  ...
  loop->time = 0;
  uv_update_time(loop);
  ...
}

可以看到looptime字段先被賦值為0,之后調(diào)用uv_update_time函數(shù),這會將最新的計(jì)數(shù)時間賦給loop.time

初始化完成之后,default_loop_struct.time就有了一個初始值,與時間有關(guān)的操作都會與此值進(jìn)行比較從而確定是否調(diào)用相應(yīng)回調(diào)函數(shù)。

libuv的事件調(diào)度核心

前面提到uv_run函數(shù)就是libuv庫實(shí)現(xiàn)event loop的核心部分,下面是其流程圖:

這里簡述一下上面與定時器相關(guān)的邏輯:

更新當(dāng)前looptime字段,這個字段標(biāo)志著當(dāng)前loop概念下的“現(xiàn)在”;

檢查loop是否alive,也就是說檢查loop中是否還有需要處理的任務(wù)(handlers/requests),如果沒有就不必循環(huán)了;

檢查注冊過的timer,如果某一個timer中指定的時間落后于當(dāng)前時間了,說明該timer已到時,于是執(zhí)行其對應(yīng)的回調(diào)函數(shù);

執(zhí)行一次I/O polling(即阻塞住線程,等待I/O事件發(fā)生),如果在下一個timer到期時還沒有任何I/O完成,則停止等待,執(zhí)行下一個timer的回調(diào)。
如果發(fā)生了I/O事件,則執(zhí)行對應(yīng)的回調(diào);由于執(zhí)行回調(diào)的時間里可能又有timer到期了,這里要再次檢查timer并執(zhí)行回調(diào)。
(實(shí)際上(4.)這里比較復(fù)雜,不僅僅是一步操作,這樣描述僅是為了不涉及其他細(xì)節(jié),而專注于timer的實(shí)現(xiàn)。)

Node會一直調(diào)用uv_run直到loop不再alive。

Node中的timer_wrap與timers

Node中有一個TimerWrap類,被注冊為Node內(nèi)部的timer_wrap模塊。

NODE_MODULE_CONTEXT_AWARE_BUILTIN(timer_wrap, node::TimerWrap::Initialize)

其中TimerWrap類基本上就是對uv_timer_t的一個直接封裝,NODE_MODULE_CONTEXT_AWARE_BUILTIN是Node用于注冊built-in模塊的宏。

經(jīng)過這一步操作,JavaScript就可以拿到這個模塊進(jìn)行操作了。src/lib/timers.js文件使用JavaScript的形式把timer_wrap的功能封裝起來,并導(dǎo)出了exports.setTimeout, exports.setInterval, exports.setImmediate等函數(shù)。

Node啟動與global初始化

上一篇提到Node啟動時會載入執(zhí)行環(huán)境LoadEnvironment(env),這個函數(shù)中非常重要的一步就是載入src/node.js并執(zhí)行,src/node.js會載入指定的模塊并初始化globalprocess。當(dāng)然,setTimeout等函數(shù)也會被src/node.js綁定到global對象上。

至此,setTimeout/setInterval這類定時器函數(shù)已經(jīng)可以為JavaScript所用了。

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

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

相關(guān)文章

  • 初窺JavaScript事件機(jī)制實(shí)現(xiàn)(一)—— Node.js事件驅(qū)動實(shí)現(xiàn)概覽

    摘要:如果當(dāng)前沒有事件也沒有定時器事件,則返回。相關(guān)資料關(guān)于的架構(gòu)及設(shè)計(jì)思路的事件討論了使用線程池異步運(yùn)行代碼。下一篇初窺事件機(jī)制的實(shí)現(xiàn)二中定時器的實(shí)現(xiàn) 在瀏覽器中,事件作為一個極為重要的機(jī)制,給予JavaScript響應(yīng)用戶操作與DOM變化的能力;在Node.js中,事件驅(qū)動模型則是其高并發(fā)能力的基礎(chǔ)。 學(xué)習(xí)JavaScript也需要了解它的運(yùn)行平臺,為了更好的理解JavaScript的事...

    lavor 評論0 收藏0
  • Node_深入淺出Node

    摘要:簡介項(xiàng)目命名為就是一個服務(wù)器單純開發(fā)一個服務(wù)器的想法,變成構(gòu)建網(wǎng)絡(luò)應(yīng)用的一個基本框架發(fā)展為一個強(qiáng)制不共享任何資源的單線程,單進(jìn)程系統(tǒng)。單線程弱點(diǎn)無法利用多核錯誤會引起整個應(yīng)用退出,應(yīng)用的健壯性大量計(jì)算占用導(dǎo)致無法繼續(xù)調(diào)用異步。 NodeJs簡介 Ryan Dahl項(xiàng)目命名為:web.js 就是一個Web服務(wù)器.單純開發(fā)一個Web服務(wù)器的想法,變成構(gòu)建網(wǎng)絡(luò)應(yīng)用的一個基本框架.Node發(fā)展...

    shinezejian 評論0 收藏0
  • JavaScript執(zhí)行機(jī)制

    摘要:事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。最后的最后是一門單線程語言是的執(zhí)行機(jī)制部分內(nèi)容轉(zhuǎn)自 1.單線程 javascript是一門單線程語言 2.javascript事件循環(huán) 同步任務(wù) 異步任務(wù) showImg(https://segmentfault.com/img/bVbufUd?w=1268&h=1062);除了廣義的同步任務(wù)和異步任務(wù),我們對任務(wù)有更精細(xì)的定義...

    ralap 評論0 收藏0
  • 事件循環(huán)與任務(wù)隊(duì)列

    摘要:需要注意的是,定時器比較特殊,并沒有把回調(diào)函數(shù)掛在事件循環(huán)隊(duì)列中,它所做的就是設(shè)置一個定時器,當(dāng)定時器到時后,環(huán)境會把你的回調(diào)函數(shù)放在事件循環(huán)中,這樣,在未來某個時刻的會被取出執(zhí)行。 Author: bugall Wechat: bugallF Email: [email protected] Github: https://github.com/bugall 一...

    SQC 評論0 收藏0
  • 瀏覽器與Node事件循環(huán)(Event Loop)有何區(qū)別?

    摘要:事件觸發(fā)線程主要負(fù)責(zé)將準(zhǔn)備好的事件交給引擎線程執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 Fundebug經(jīng)作者浪里行舟授權(quán)首發(fā),未經(jīng)同意請勿轉(zhuǎn)載。 前言 本文我們將會介紹 JS 實(shí)現(xiàn)異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實(shí)是不相同的。 一、線程與進(jìn)程 1. 概念 我們經(jīng)常說 JS 是單線程執(zhí)行的,...

    TANKING 評論0 收藏0

發(fā)表評論

0條評論

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