首頁 web前端 js教程 詳解Node.js:events事件模組

詳解Node.js:events事件模組

Dec 05, 2016 pm 01:37 PM
node.js

Nodejs的大部分核心API都是基於非同步事件驅動設計的,所有可以分發事件的物件都是EventEmitter類別的實例。

大家知道,由於nodejs是單執行緒運作的,所以nodejs需要藉助事件輪詢,不斷去查詢事件佇列中的事件訊息,然後執行該事件對應的回呼函數,有點類似windows的訊息映射機制。至於更細的實現環節,可以另行查找資料。

下面介紹EventEmitter的使用。

1、監聽事件和分發事件

EventEmitter實例可以使用on或addListener監聽事件,emit()方法分發事件,如下圖:

const events = require('events'),
   EventEmitter = events.EventEmitter,
   util = require('util');
function myEmiter(){
  EventEmitter.call(this);
};
util.inherits(myEmiter,EventEmitter);//继承EventEmitter类
const myEmitterIns = new myEmiter();
myEmitterIns.on('data',(o)=>{
  console.log('receive the data:'+o.a);
});
登入後複製

  

執行結果如下:

E:developmentdocumentnodejsdemo>node event-example.js

receive the data:1

2、向事件監聽回調函數傳遞參數

2、向事件監聽回調函數傳遞參數


從上面的例子可以看出傳遞任意的參數集合給回呼函數,需要注意的一點是this關鍵字指向的是呼叫emit方法的EventEmiter實例,但在箭頭函數中例外,this指向的是全域this,因為箭頭函數中的this是在定義時綁定。如下圖所示:

class myEmiter extends EventEmitter{}//继承EventEmitter类
const myEmitterIns = new myEmiter();
 
myEmitterIns.on('data',(o)=>{
  console.log('receive the data:'+o.a);
});
myEmitterIns.emit('data',{a:1});
登入後複製

   

執行結果如下:

E:developmentdocumentnodejsdemo>node event-example.js

:Function 中: ], data1: [Function] },

_eventsCount: 2,

_maxListeners: undefined }

箭頭回呼函數中this:

{}

這裡講到箭頭函數中的this,就順便說一下,為什麼箭頭函數能夠實現定義時綁定this,就是因為箭頭函數內部根本就沒有綁定this的機制,它使用的是外層作用域的this,因此它也不能作為建構函數。

3、事件監聽程序的執行順序


EventEmiter實例可以綁定多個事件,當我們順序觸發這些事件時,EventEmiter會以同步模式執行,既第一個事件處理函數沒有完成,便不會觸發下一個事件,如下所示:

class myEmiter extends EventEmitter{}
const myEmitterIns = new myEmiter();
myEmitterIns.on('data',function(data){
  console.log("普通回调函数中this:");
  console.log(this);
});
myEmitterIns.on('data1',(data1)=>{
  console.log("箭头回调函数中this:");
  console.log(this);
});
myEmitterIns.emit('data',{a:1});
myEmitterIns.emit('data1',{a:1});
登入後複製

   


執行結果如下:

E:developmentdocumentnodejsdemo>node event-example.jso

data事件執行了: 4721.40121.當然我們可以在回呼函數中使用非同步操作,例如setTimeout,setImmediate或process.nextTick()等,從而實現非同步操作,例如setTimeout,setImmediate或process.nextTick()等,從而實現非同步的效果,如下所示:

class myEmiter extends EventEmitter{}
const myEmitterIns = new myEmiter();
myEmitterIns.on('data',function(data){
  console.time('data事件执行了');
  for(var i = 0 ; i< 100000; i++)
    for(var j = 0 ; j< 100000; j++)
      ;
  console.timeEnd(&#39;data事件执行了&#39;);
});
myEmitterIns.on(&#39;data1&#39;,(data1)=>{
  console.log("data1事件开始执行...");
});
myEmitterIns.emit(&#39;data&#39;,{a:1});
myEmitterIns.emit(&#39;data1&#39;,{a:1});
登入後複製

   

的執行結果node event-example.js

data1事件執行了...
data事件執行了...

4、一次性事件監聽

EventEmiter可以使用once監聽某個事件,則該事件處理程序只會觸發一次,之後emit該事件都會被忽略,因為監聽程式被註銷了,如下所示:

myEmitterIns.on(&#39;data&#39;,function(data){
  setImmediate(()=>{
    console.log(&#39;data事件执行了...&#39;);
  });
});
登入後複製

   

執行結果如下:

E:developmentdocumentnodejsdemonode

從上面的結果看出,'one'事件只執行了一次。

5、移除事件綁定

類似DOM事件監聽,EventEmiter也可以移除事件綁定,利用removeListener(eventName,listener)方法解除某個事件的綁定,因此回呼函數listenerener必須是命名函數,不然找不到該函數,因為函數是引用類型,就算函數體是一樣,也不是同一個函數,如下:

myEmitterIns.once(&#39;one&#39;,(data)=>{
  console.log(data);
});
myEmitterIns.emit(&#39;one&#39;,&#39;this is first call!&#39;);
myEmitterIns.emit(&#39;one&#39;,&#39;this is second call!&#39;);
登入後複製

   

執行結果如下:

E:deopmentdocumnodejsdeopmentdocumnode event-example.js

hello data!

E:developmentdocumentnodejsdemo>


從執行結果可以看出,data事件使用的是匿名函數,因此沒有被移除掉,而data1事件則成功解除綁定了。這裡需要注意一點的是emit觸發某個事件後,所有跟該事件綁定的回調函數都會被調用,即使你在某個回調函數中使用removeListener函數移除掉另一個回調也沒有用,但是隨後的事件隊列是移除了該回呼的。如下所示:

myEmitterIns.on(&#39;data&#39;,function(e){
  console.log(e);
});
myEmitterIns.removeListener(&#39;data&#39;,function(e){
  console.log(e);
});
myEmitterIns.emit(&#39;data&#39;,&#39;hello data!&#39;);
function deal(e){
  console.log(e);
}
myEmitterIns.on(&#39;data1&#39;,deal);
myEmitterIns.removeListener(&#39;data1&#39;,deal);
myEmitterIns.emit(&#39;data1&#39;,&#39;hello data1!&#39;);
登入後複製

6、取得事件監聽數量和監聽函數

使用emitter.listenerCount(eventName)函數取得指定事件的監聽數量,函數emitter.listeners(eventName)則可以用來取得指定事件的所有監聽函數,使用如下所示:

function dealData1(e){
  console.log(&#39;data事件执行了...A&#39;);
}
myEmitterIns.on(&#39;data&#39;,function(e){
  console.log(e);
  myEmitterIns.removeListener(&#39;data&#39;,dealData1);//这里解除dealData1的绑定
});
myEmitterIns.on(&#39;data&#39;,dealData1);
myEmitterIns.emit(&#39;data&#39;,&#39;data事件执行了...B&#39;);
/*执行结果为:
 data事件执行了...B
 data事件执行了...A
*/
//再次触发该事件时,dealData1回调已经被解除绑定了
myEmitterIns.emit(&#39;data&#39;,&#39;data事件执行了...&#39;);
//data事件执行了...
   
另外可以使用removeAllListeners()解除所有事件的绑定。
登入後複製

   


執行結果如下:

E:developmentdocumentnodejsdemo>node event-example.js Function: cbA], [Function: cbB] ]

7、獲取和設定emitter的最大監聽數量

nodejs對同一事件的監聽數量建議不宜超過10個,這個可以查看EventEmitter.defaultMaxListeners屬性便可得知,如下所示:

var cbA = ()=>{},
  cbB = ()=>{};
var emitter = new myEmiter();
emitter.on(&#39;data&#39;,cbA);
emitter.on(&#39;data&#39;,cbB);
console.log(&#39;emitter实例的data事件绑定了%d个回调函数&#39;,emitter.listenerCount(&#39;data&#39;));
console.log(&#39;它们是:&#39;,emitter.listeners(&#39;data&#39;));
登入後複製

   

emitter透過getMaxListeners()方法取得最大監聽數量以及setMaxListeners(n)方法設定最大監聽數量,如下所示:

console.log(EventEmitter.defaultMaxListeners);//结果为10个
登入後複製
   

執行結果如下:

E:developmentdocumentnodejsdemo>node event-example.js
emitter的事件最大監聽數是:1
(node:6808) Warning: Possible EventEmitter memory
(node:6808) Warning: Possible EventEmitter memory leakdata .m .setMaxListeners() to increase limit

如上結果所示,如果設定了最大監聽數量,則同一事件的監聽最好不要超過該最大值,否則很可能發送記憶體洩漏。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node.js 19正式發布,聊聊它的 6 大功能! Node.js 19正式發布,聊聊它的 6 大功能! Nov 16, 2022 pm 08:34 PM

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

一起聊聊Node中的事件循環 一起聊聊Node中的事件循環 Apr 11, 2023 pm 07:08 PM

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

聊聊Node.js中的 GC (垃圾回收)機制 聊聊Node.js中的 GC (垃圾回收)機制 Nov 29, 2022 pm 08:44 PM

Node.js 是如何做 GC (垃圾回收)的?下面這篇文章就來帶大家了解一下。

聊聊用pkg將Node.js專案打包為執行檔的方法 聊聊用pkg將Node.js專案打包為執行檔的方法 Dec 02, 2022 pm 09:06 PM

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

See all articles