天天看點

nodejs的事件處理機制以及事件環機制nodejs的事件處理機制以及事件環機制

nodejs的事件處理機制以及事件環機制

ES6标準釋出後,module成為标準,标準的使用是以export指令導出接口,以import引入子產品,但是在我們一貫的node子產品中,我們采用的是CommonJS規範,使用require引入子產品,使用module.exports導出接口。

不把require和import整清楚,會在未來的标準程式設計中死的很難看。

require時代的子產品

node程式設計中最重要的思想之一就是子產品,而正是這個思想,讓JavaScript的大規模工程成為可能。子產品化程式設計在js界流行,也是基于此,随後在浏覽器端,requirejs和seajs之類的工具包也出現了,可以說在對應規範下,require統治了ES6之前的所有子產品化程式設計,即使現在,在ES6 module被完全實作之前,還是這樣。

node的module遵循CommonJS規範,requirejs遵循AMD,seajs遵循CMD,雖各有不同,但總之還是希望保持較為統一的代碼風格。

1.EventEmitter類

在Node.js中用于事件處理的event子產品中,定義了一個EventEmitter類.所有可能觸發的事件都是EventEmitter類子類的執行個體對象,EventEmitter類中的方法如下:

nodejs的事件處理機制以及事件環機制nodejs的事件處理機制以及事件環機制

image.png

使用on方法綁定事件處理函數
var http = require('http');
var server = http.createServer();
server.on('request',function (req,res) {
    console.log(req.url);
    res.end('hello');
});
server.listen(1337,"127.0.0.1");
           

當我們請求1337端口的時候輸出如下所示:

/                          (注解:代表程式的根目錄)
/favicon.ico                (注解:代表頁面在收藏夾中的顯示圖示)
           

在預設情況下,針對同一事件最多可以綁定10個事件處理函數:

server.setMaxListeners(10)
           

用once隻執行一次:

server.once('request',function (req,res) {
    console.log(req.url);
    res.end('hello');
});
           

2.擷取指定事件的事件處理函數的數量

var http = require('http');
var events = require('events');
var server = http.createServer();
server.on('request', function (req,res) {
if(req.url!='/favicon.ico'){
    console.log('接收到用戶端的請求');
}
});
server.on('request', function (req,res) {
if(req.url!='/favicon.ico'){
    console.log(req.url);
}
res.end();
});
server.on('request', function (req,res) {
if(req.url!='/favicon.ico'){
    console.log('發送響應完畢');
}
});

server.listen(1337,"127.0.0.1");

console.log(events.EventEmitter.listenerCount(server,'request'));
           
監聽newListener和removeListener
var http = require('http');
var server = http.createServer();
var test = function () {

    server.on('request',function (req,res) {
        console.log("發送了");
    });

}


server.on('removeListener',function (e,f) {
    console.log("對"+e+"事件取消事件處理函數");
    console.log(f);
});
server.on('newListener',function (e,f) {
    console.log("對"+e+"事件添加事件處理函數");
    console.log(f);
});


server.on('request', function (req,res) {
    if(req.url!='/favicon.ico'){
        console.log('接收到用戶端的請求');
    }
});
server.on('request', function (req,res) {
    if(req.url!='/favicon.ico'){
        console.log(req.url);
    }
    res.end();
});
server.on('request', function (req,res) {
    if(req.url!='/favicon.ico'){
        console.log('發送響應完畢');
    }
});
server.on('request',test);
server.removeListener('request',test);
server.listen(1337,"127.0.0.1");

           

3.Node.js事件環機制

事件循環定義:當線程中的I/O任務完成之後就會執行指定的回調函數,并且将這個完成的事件放在事件隊列的尾部,等待事件循環,當主線程再次循環到這個事件的時候,就會直接處理并且傳回給上層調用,這個過程就是事件循環(Event Loop)。Node.js運作的原理圖如下所示:

nodejs的事件處理機制以及事件環機制nodejs的事件處理機制以及事件環機制

這個圖是整個 Node.js 的運作原理,從左到右,從上到下,Node.js 被分為了四層,分别是 應用層、V8引擎層、Node API層和LIBUV層。

  • 應用層:即 JavaScript 互動層,常見的就是 Node.js 的子產品,比如 http,fs。
  • V8引擎層:即利用 V8 引擎來解析JavaScript 文法,進而和下層 API 互動。
  • Node API層:為上層子產品提供系統調用,一般是由 C 語言來實作,和作業系統進行互動。
  • LIBUV層:是跨平台的底層封裝,實作了 事件循環、檔案操作等,是 Node.js 實作異步的核心。

    在Node.js的内部是通過線程池來完成I/O操作的,但是LIBUV層會針對不同的作業系統平台的差異性實作了統一調用,Node.js的單線程指的是JavaScript運作在單線程中,并不是說Node.js是單線程的,Node.js是一個多線程的平台,但是對于JavaScript的處理是單線程的。

繼續閱讀