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類中的方法如下:
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運作的原理圖如下所示:
這個圖是整個 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的處理是單線程的。