欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Node.js事件循環(huán)(Event Loop)和線程池詳解

 更新時(shí)間:2015年01月28日 17:27:14   投稿:junjie  
這篇文章主要介紹了Node.js事件循環(huán)(Event Loop)和線程池詳解,這篇文章比較淺顯地探討了有關(guān)事件循環(huán)的內(nèi)部運(yùn)作機(jī)制和技術(shù)細(xì)節(jié),都是經(jīng)過(guò)深思熟慮的,需要的朋友可以參考下

Node的“事件循環(huán)”(Event Loop)是它能夠處理大并發(fā)、高吞吐量的核心。這是最神奇的地方,據(jù)此Node.js基本上可以理解成“單線程”,同時(shí)還允許在后臺(tái)處理任意的操作。這篇文章將闡明事件循環(huán)是如何工作的,你也可以感受到它的神奇。

事件驅(qū)動(dòng)編程

理解事件循環(huán),首先要理解事件驅(qū)動(dòng)編程(Event Driven Programming)。它出現(xiàn)在1960年。如今,事件驅(qū)動(dòng)編程在UI編程中大量使用。JavaScript的一個(gè)主要用途是與DOM交互,所以使用基于事件的API是很自然的。

簡(jiǎn)單地定義:事件驅(qū)動(dòng)編程通過(guò)事件或狀態(tài)的變化來(lái)進(jìn)行應(yīng)用程序的流程控制。一般通過(guò)事件監(jiān)聽(tīng)實(shí)現(xiàn),一旦事件被檢測(cè)到(即狀態(tài)改變)則調(diào)用相應(yīng)的回調(diào)函數(shù)。聽(tīng)起來(lái)很熟悉?其實(shí)這就是Node.js事件循環(huán)的基本工作原理。

如果你熟悉客戶端JavaScript的開(kāi)發(fā),想一想那些.on*()方法,如element.onclick(),他們用來(lái)與DOM元素相結(jié)合,傳遞用戶交互。這個(gè)工作模式允許在單個(gè)實(shí)例上觸發(fā)多個(gè)事件。Node.js通過(guò)EventEmitter(事件發(fā)生器)觸發(fā)這種模式,如在服務(wù)器端的Socket和 “http”模塊中??梢詮囊粋€(gè)單一實(shí)例觸發(fā)一種或一種以上的狀態(tài)改變。

另一種常見(jiàn)的模式是表達(dá)成功succeed和失敗fail。現(xiàn)在一般有兩種常見(jiàn)的實(shí)現(xiàn)方式。首先是將“Error異?!眰魅牖卣{(diào),一般作為第一個(gè)參數(shù)傳遞給回調(diào)函數(shù)。第二種即使用Promises設(shè)計(jì)模式,已經(jīng)加入了ES6。注* Promise模式采用類似jQuery的函數(shù)鏈?zhǔn)綍?shū)寫(xiě)方式,以避免深層次的回調(diào)函數(shù)嵌套,如:

復(fù)制代碼 代碼如下:

$.getJSON('/getUser').done(successHandler).fail(failHandler)

“fs”(filesystem)模塊大多采用往回調(diào)中傳入異常的風(fēng)格。在技術(shù)上觸發(fā)某些調(diào)用,例如fs.readFile()附加事件,但該API只是為了提醒用戶,用來(lái)表達(dá)操作成功或失敗。選擇這樣的API是出于架構(gòu)的考慮,而非技術(shù)的限制。

一個(gè)常見(jiàn)的誤解是,事件發(fā)生器(event emitters)在觸發(fā)事件時(shí)也是天生異步的,但這是不正確的。下面是一個(gè)簡(jiǎn)單的代碼片段,以證明這一點(diǎn)。

復(fù)制代碼 代碼如下:

function MyEmitter() {
  EventEmitter.call(this);
}
util.inherits(MyEmitter, EventEmitter);

MyEmitter.prototype.doStuff = function doStuff() {
  console.log('before')
  emitter.emit('fire')
  console.log('after')}
};

var me = new MyEmitter();
me.on('fire', function() {
  console.log('emit fired');
});

me.doStuff();
// 輸出:
// before
// emit fired
// after

注* 如果 emitter.emit 是異步的,則輸出應(yīng)該為
// before
// after
// emit fired


EventEmitter經(jīng)常表現(xiàn)地很異步,因?yàn)樗?jīng)常用于通知需要異步完成的操作,但EventEmitter API本身是完全同步的。監(jiān)聽(tīng)函數(shù)內(nèi)部可以按異步執(zhí)行,但請(qǐng)注意,所有的監(jiān)聽(tīng)函數(shù)將按被添加的順序同步執(zhí)行。

機(jī)制概述和線程池

Node本身依賴多個(gè)庫(kù)。其中之一是libuv,神奇的處理異步事件隊(duì)列和執(zhí)行的庫(kù)。

Node利用盡可能多的利用操作系統(tǒng)內(nèi)核實(shí)現(xiàn)現(xiàn)有的功能。像生成響應(yīng)請(qǐng)求(request),轉(zhuǎn)發(fā)連接(connections)并委托給系統(tǒng)處理。例如,傳入的連接通過(guò)操作系統(tǒng)進(jìn)行隊(duì)列管理,直到它們可以由Node處理。

您可能聽(tīng)說(shuō)過(guò),Node有一個(gè)線程池,你可能會(huì)疑惑:“如果Node會(huì)按次序處理任務(wù),為什么還需要一個(gè)線程池?”這是因?yàn)樵趦?nèi)核中,不是所有任務(wù)都是按異步執(zhí)行的。在這種情況下,Node.JS必須能在操作時(shí)將線程鎖定一段時(shí)間,以便它可以繼續(xù)執(zhí)行事件循環(huán)而不會(huì)被阻塞。

下面是一個(gè)簡(jiǎn)單的示例圖,來(lái)表示他內(nèi)部的運(yùn)行機(jī)制:


            ┌───────────────────────┐
╭──►│         timers                                           │
 │         └───────────┬───────────┘
 │         ┌───────────┴───────────┐
 │         │   pending callbacks                             │
 │         └───────────┬───────────┘          ┌──────────────┐
 │         ┌───────────┴───────────┐          │  incoming:                    │
 │          │          poll                                               │◄──┤ connections,                │
 │         └───────────┬───────────┘          │  data, etc.                     │
 │         ┌───────────┴───────────┐          └──────────────┘
╰───┤      setImmediate                                  │
             └───────────────────────┘

關(guān)于事件循環(huán)的內(nèi)部運(yùn)行機(jī)制,有一些理解困難的地方:

所有回調(diào)都會(huì)經(jīng)由process.nextTick(),在事件循環(huán)(例如,定時(shí)器)一個(gè)階段的結(jié)束并轉(zhuǎn)換到下一階段之前預(yù)設(shè)定。這就會(huì)避免潛在的遞歸調(diào)用process.nextTick(),而造成的無(wú)限循環(huán)。
“Pending callbacks(待回調(diào))”,是回調(diào)隊(duì)列中不會(huì)被任何其他事件循環(huán)周期處理(例如,傳遞給fs.write)的回調(diào)。

Event Emitter 和 Event Loop

通過(guò)創(chuàng)建EventEmitter,可簡(jiǎn)化與事件循環(huán)的交互。它是一個(gè)通用的封裝,可以讓你更容易地創(chuàng)建基于事件的API。關(guān)于這兩者如何互動(dòng)往往讓開(kāi)發(fā)者感到混亂。

下面的例子表明,忘記了事件是同步觸發(fā)的,可能導(dǎo)致事件被錯(cuò)過(guò)。

復(fù)制代碼 代碼如下:

// v0.10以后,不再需要require('events').EventEmitter
var EventEmitter = require('events');
var util = require('util');

function MyThing() {
  EventEmitter.call(this);

  doFirstThing();
  this.emit('thing1');
}
util.inherits(MyThing, EventEmitter);

var mt = new MyThing();

mt.on('thing1', function onThing1() {
  // 抱歉,這個(gè)事件永遠(yuǎn)不會(huì)發(fā)生
});


上面的'thing1'事件,永遠(yuǎn)不會(huì)被MyThing()捕獲,因?yàn)镸yThing()必須在實(shí)例化后才能偵聽(tīng)事件。下面的是一個(gè)簡(jiǎn)單的解決方法,不必添加任何額外的閉包:
復(fù)制代碼 代碼如下:

var EventEmitter = require('events');
var util = require('util');

function MyThing() {
  EventEmitter.call(this);

  doFirstThing();
  setImmediate(emitThing1, this);
}
util.inherits(MyThing, EventEmitter);

function emitThing1(self) {
  self.emit('thing1');
}

var mt = new MyThing();

mt.on('thing1', function onThing1() {
  // 執(zhí)行了
});

下面的方案也可以工作,不過(guò)要損失一些性能:

復(fù)制代碼 代碼如下:

function MyThing() {
  EventEmitter.call(this);

  doFirstThing();
  // 使用 Function#bind() 會(huì)損失性能
  setImmediate(this.emit.bind(this, 'thing1'));
}
util.inherits(MyThing, EventEmitter);


另一個(gè)問(wèn)題是觸發(fā)Error(異常)。找出您應(yīng)用程序中的問(wèn)題已經(jīng)很難了,但沒(méi)了調(diào)用堆棧(注* e.stack),則幾乎不可能調(diào)試。當(dāng)Error被遠(yuǎn)端的異步請(qǐng)求調(diào)用堆棧將丟失。有兩個(gè)可行的解決方案:同步觸發(fā)或確保Error跟其他重要信息一起傳入。下面的例子演示了這兩種解決方案:
復(fù)制代碼 代碼如下:

MyThing.prototype.foo = function foo() {
  // 這個(gè) error 會(huì)被異步觸發(fā)
  var er = doFirstThing();
  if (er) {
    // 在觸發(fā)時(shí),需要?jiǎng)?chuàng)建一個(gè)新的保留現(xiàn)場(chǎng)調(diào)用堆棧信息的error
    setImmediate(emitError, this, new Error('Bad stuff'));
    return;
  }

  // 觸發(fā)error,馬上處理(同步)
  var er = doSecondThing();
  if (er) {
    this.emit('error', 'More bad stuff');
    return;
  }
}


審時(shí)度勢(shì)。當(dāng)error被觸發(fā)時(shí),是有可能被立即處理的?;蛘?,它可能是一些瑣碎的,可以很容易處理,或在以后再處理的異常。此外通過(guò)一個(gè)構(gòu)造函數(shù),傳遞Error也不是一個(gè)好主意,因?yàn)闃?gòu)造出來(lái)的對(duì)象實(shí)例很有可能是不完整的。剛才直接拋出Error的情況是個(gè)例外。

結(jié)束語(yǔ)

這篇文章比較淺顯地探討了有關(guān)事件循環(huán)的內(nèi)部運(yùn)作機(jī)制和技術(shù)細(xì)節(jié)。都是經(jīng)過(guò)深思熟慮的。另一篇文章會(huì)討論事件循環(huán)與系統(tǒng)內(nèi)核的交互,并展現(xiàn)NodeJS異步運(yùn)行的魔力。

相關(guān)文章

  • Node.js中常規(guī)的文件操作總結(jié)

    Node.js中常規(guī)的文件操作總結(jié)

    關(guān)于Node.js中文件的常規(guī)操作,主要的就是fs這個(gè)模塊。對(duì)于node.js中fs模塊提供的API很多,但是其所有的方法均有同步和異步的形式。那么下面這篇文章我們就來(lái)詳細(xì)介紹下關(guān)于Node.js中文件的常規(guī)操作,有需要的朋友們可以參考借鑒。
    2016-10-10
  • node.js中實(shí)現(xiàn)kindEditor圖片上傳功能的方法教程

    node.js中實(shí)現(xiàn)kindEditor圖片上傳功能的方法教程

    最近在做一個(gè)類似于論壇的系統(tǒng),帖子需要進(jìn)行圖文并茂的顯示,所以用到了富文本編輯器:kindeditor,下面這篇文章主要給大家介紹了在node.js中實(shí)現(xiàn)kindEditor圖片上傳功能的方法教程,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-04-04
  • node 可讀流與可寫(xiě)流的運(yùn)用詳解

    node 可讀流與可寫(xiě)流的運(yùn)用詳解

    這篇文章主要為大家介紹了node 可讀流與可寫(xiě)流的運(yùn)用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Node.js API詳解之 os模塊用法實(shí)例分析

    Node.js API詳解之 os模塊用法實(shí)例分析

    這篇文章主要介紹了Node.js API詳解之 os模塊用法,結(jié)合實(shí)例形式分析了Node.js API中os模塊基本功能、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • node.js中的fs.chmod方法使用說(shuō)明

    node.js中的fs.chmod方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.chmod方法使用說(shuō)明,本文介紹了fs.chmod方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • 如何利用nodejs自動(dòng)定時(shí)發(fā)送郵件提醒(超實(shí)用)

    如何利用nodejs自動(dòng)定時(shí)發(fā)送郵件提醒(超實(shí)用)

    這篇文章主要給大家介紹了關(guān)于如何利用nodejs實(shí)現(xiàn)自動(dòng)定時(shí)發(fā)送郵件提醒的相關(guān)資料,這個(gè)功能非常實(shí)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Node.js中的child_process模塊詳解

    Node.js中的child_process模塊詳解

    這篇文章主要給大家介紹了關(guān)于Node.js中child_process模塊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • 使用node操作SQLite的方法

    使用node操作SQLite的方法

    SQLite是一種輕量級(jí)的嵌入式關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它以庫(kù)的形式存在,可以嵌入到應(yīng)用程序中,使用Node.js操作SQLite數(shù)據(jù)庫(kù)有多種方式,其中常用的方式包括使用sqlite3模塊、sequelize模塊和knex模塊,本文將詳細(xì)的給大家介紹這幾種方式,需要的朋友可以參考下
    2023-10-10
  • node快速搭建后臺(tái)的實(shí)現(xiàn)步驟

    node快速搭建后臺(tái)的實(shí)現(xiàn)步驟

    本文主要介紹了node快速搭建后臺(tái),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • node.js之基礎(chǔ)加密算法模塊crypto詳解

    node.js之基礎(chǔ)加密算法模塊crypto詳解

    這篇文章主要介紹了node.js之基礎(chǔ)加密算法模塊crypto詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09

最新評(píng)論