node的EventEmitter模塊基本用法簡(jiǎn)單實(shí)現(xiàn)示例
導(dǎo)讀
node的事件模塊只包含了一個(gè)類(lèi):EventEmitter。這個(gè)類(lèi)在node的內(nèi)置模塊和第三方模塊中大量使用。EventEmitter本質(zhì)上是一個(gè)觀察者模式的實(shí)現(xiàn),這種模式可以擴(kuò)展node在多個(gè)進(jìn)程或網(wǎng)絡(luò)中運(yùn)行。本文從node的EventEmitter的使用出發(fā),循序漸進(jìn)的實(shí)現(xiàn)一個(gè)完整的EventEmitter模塊。
- EventEmitter模塊的基本用法和簡(jiǎn)單實(shí)現(xiàn)
- node中常用的EventEmitter模塊的API
- EventEmitter模塊的異常處理
- 完整的實(shí)現(xiàn)一個(gè)EventEmitter模塊
原文地址:https://github.com/forthealll...
如果文章對(duì)您有幫助,您的star是對(duì)我最好的鼓勵(lì)~
EventEmitter模塊的基本用法和簡(jiǎn)單實(shí)現(xiàn)
(1) EventEmitter模塊的基本用法
首先先了解一下EventEmitter模塊的基本用法,EventEmitter本質(zhì)上是一個(gè)觀察者模式的實(shí)現(xiàn),所謂觀察者模式:
它定義了對(duì)象間的一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知。
因此最基本的EventEmitter功能,包含了一個(gè)觀察者和一個(gè)被監(jiān)聽(tīng)的對(duì)象,對(duì)應(yīng)的實(shí)現(xiàn)就是EventEmitter中的on和emit:
var events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.on('say',function(name){
console.log('Hello',name);
})
eventEmitter.emit('say','Jony yu');eventEmitter是EventEmitter模塊的一個(gè)實(shí)例,eventEmitter的emit方法,發(fā)出say事件,通過(guò)eventEmitter的on方法監(jiān)聽(tīng),從而執(zhí)行相應(yīng)的函數(shù)。
(2) 簡(jiǎn)單實(shí)現(xiàn)一個(gè)EventEmitter模塊
根據(jù)上述的例子,我們知道了EventEmitter模塊的基礎(chǔ)功能emit和on。下面我們實(shí)現(xiàn)一個(gè)包含emit和on方法的EventEmitter類(lèi)。
on(eventName,callback)方法傳入兩個(gè)參數(shù),一個(gè)是事件名(eventName),另一個(gè)是相應(yīng)的回調(diào)函數(shù),我們選擇在on的時(shí)候針對(duì)事件名添加監(jiān)聽(tīng)函數(shù),用對(duì)象來(lái)包含所有事件。在這個(gè)對(duì)象中對(duì)象名表示事件名(eventName),而對(duì)象的值是一個(gè)數(shù)組,表示該事件名所對(duì)應(yīng)的執(zhí)行函數(shù)。
emit(eventName,...arg)方法傳入的參數(shù),第一個(gè)為事件名,其他參數(shù)事件對(duì)應(yīng)的執(zhí)行函數(shù)中的實(shí)參,emit方法的功能就是從事件對(duì)象中,尋找對(duì)應(yīng)key為eventName的屬性,執(zhí)行該屬性所對(duì)應(yīng)的數(shù)組里面每一個(gè)執(zhí)行函數(shù)。
下面來(lái)實(shí)現(xiàn)一個(gè)EventEmitter類(lèi)
class EventEmitter{
constructor(){
this.handler={};
}
on(eventName,callback){
if(!this.handles){
this.handles={};
}
if(!this.handles[eventName]){
this.handles[eventName]=[];
}
this.handles[eventName].push(callback);
}
emit(eventName,...arg){
if(this.handles[eventName]){
for(var i=0;i<this.handles[eventName].length;i++){
this.handles[eventName][i](...arg);
}
}
}
}上述就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的EventEmitter類(lèi),下面來(lái)實(shí)例化:
let event=new EventEmitter();
event.on('say',function(str){
console.log(str);
});
event.emit('say','hello Jony yu');
//輸出hello Jony yunode中常用的EventEmitter模塊的API
跟在上述簡(jiǎn)單的EventEmitter模塊不同,node的EventEmitter還包含了很多常用的API,我們一一來(lái)介紹幾個(gè)實(shí)用的API.
| 方法名 | 方法描述 | |
|---|---|---|
| addListener(event, listener) | 為指定事件添加一個(gè)監(jiān)聽(tīng)器到監(jiān)聽(tīng)器數(shù)組的尾部。 | |
| prependListener(event,listener) | 與addListener相對(duì),為指定事件添加一個(gè)監(jiān)聽(tīng)器到監(jiān)聽(tīng)器數(shù)組的頭部。 | |
| on(event, listener) | 其實(shí)就是addListener的別名 | |
| once(event, listener) | 為指定事件注冊(cè)一個(gè)單次監(jiān)聽(tīng)器,即 監(jiān)聽(tīng)器最多只會(huì)觸發(fā)一次,觸發(fā)后立刻解除該監(jiān)聽(tīng)器。 | |
| removeListener(event, listener) | 移除指定事件的某個(gè)監(jiān)聽(tīng)器,監(jiān)聽(tīng)器必須是該事件已經(jīng)注冊(cè)過(guò)的監(jiān)聽(tīng)器 | |
| off(event, listener) | removeListener的別名 | |
| removeAllListeners([event]) | 移除所有事件的所有監(jiān)聽(tīng)器, 如果指定事件,則移除指定事件的所有監(jiān)聽(tīng)器。 | |
| setMaxListeners(n) | 默認(rèn)情況下, EventEmitters 如果你添加的監(jiān)聽(tīng)器超過(guò) 10 個(gè)就會(huì)輸出警告信息。 setMaxListeners 函數(shù)用于提高監(jiān)聽(tīng)器的默認(rèn)限制的數(shù)量。 | |
| listeners(event) | 返回指定事件的監(jiān)聽(tīng)器數(shù)組。 | |
| emit(event, [arg1], [arg2], [...]) | 按參數(shù)的順序執(zhí)行每個(gè)監(jiān)聽(tīng)器,如果事件有注冊(cè)監(jiān)聽(tīng)返回 true,否則返回 false。 |
除此之外,還有2個(gè)特殊的,不需要手動(dòng)添加,node的EventEmitter模塊自帶的特殊事件:
| 事件名 | 事件描述 | |
|---|---|---|
| newListener | 該事件在添加新事件監(jiān)聽(tīng)器的時(shí)候觸發(fā) | |
| removeListener | 從指定監(jiān)聽(tīng)器數(shù)組中刪除一個(gè)監(jiān)聽(tīng)器。需要注意的是,此操作將會(huì)改變處于被刪監(jiān)聽(tīng)器之后的那些監(jiān)聽(tīng)器的索引 |
上述node的EventEmitter的模塊看起來(lái)很多很復(fù)雜,其實(shí)上述的API中包含了一些別名,仔細(xì)整理,理解其使用和實(shí)現(xiàn)不是很困難,下面一一對(duì)比和介紹上述的API。
(1) addListener和removeListener、on和off方法
addListener(eventName,listener)的作用是為指定事件添加一個(gè)監(jiān)聽(tīng)器. 其別名為on
removeListener(eventName,listener)的作用是為移除某個(gè)事件的監(jiān)聽(tīng)器. 其別名為off
再次需要強(qiáng)調(diào)的是:addListener的別名是on,removeListener的別名是off
EventEmitter.prototype.on=EventEmitter.prototype.addListener EventEmitter.prototype.off=EventEmitter.prototype.removeListener
接著我們來(lái)看具體的用法:
var events=require('events');
var emitter=new events.EventEmitter();
function hello1(name){
console.log("hello 1",name);
}
function hello2(name){
console.log("hello 2",name);
}
emitter.addListener('say',hello1);
emitter.addListener('say',hello2);
emitter.emit('say','Jony');
//輸出hello 1 Jony
//輸出hello 2 Jony
emitter.removeListener('say',hello1);
emitter.emit('say','Jony');
//相應(yīng)的監(jiān)聽(tīng)say事件的hello1事件被移除
//只輸出hello 2 Jony(2) removeListener和removeAllListeners
removeListener指的是移除一個(gè)指定事件的某一個(gè)監(jiān)聽(tīng)器,而removeAllListeners指的是移除某一個(gè)指定事件的全部監(jiān)聽(tīng)器。
這里舉例一個(gè)removeAllListeners的例子:
var events=require('events');
var emitter=new events.EventEmitter();
function hello1(name){
console.log("hello 1",name);
}
function hello2(name){
console.log("hello 2",name);
}
emitter.addListener('say',hello1);
emitter.addListener('say',hello2);
emitter.removeAllListeners('say');
emitter.emit('say','Jony');
//removeAllListeners移除了所有關(guān)于say事件的監(jiān)聽(tīng)
//因此沒(méi)有任何輸出(3) on和once方法
on和once的區(qū)別是:
on的方法對(duì)于某一指定事件添加的監(jiān)聽(tīng)器可以持續(xù)不斷的監(jiān)聽(tīng)相應(yīng)的事件,而once方法添加的監(jiān)聽(tīng)器,監(jiān)聽(tīng)一次后,就會(huì)被消除。
比如on方法(跟addListener相同):
var events=require('events');
var emitter=new events.EventEmitter();
function hello(name){
console.log("hello",name);
}
emitter.on('say',hello);
emitter.emit('say','Jony');
emitter.emit('say','yu');
emitter.emit('say','me');
//會(huì)一次輸出 hello Jony、hello yu、hello me也就是說(shuō)on方法監(jiān)聽(tīng)的事件,可以持續(xù)不斷的被觸發(fā)。
(4) 兩個(gè)特殊的事件newListener和removeListener
我們知道當(dāng)實(shí)例化EventEmitter模塊之后,監(jiān)聽(tīng)對(duì)象是一個(gè)對(duì)象,包含了所有的監(jiān)聽(tīng)事件,而這兩個(gè)特殊的方法就是針對(duì)監(jiān)聽(tīng)事件的添加和移除的。
newListener:在添加新事件監(jiān)聽(tīng)器觸發(fā)removeListener:在移除事件監(jiān)聽(tīng)器時(shí)觸發(fā)
以newListener為例,會(huì)在添加新事件監(jiān)聽(tīng)器的時(shí)候觸發(fā):
var events=require('events');
var emitter=new events.EventEmitter();
function hello(name){
console.log("hello",name);
}
emitter.on('newListener',function(eventName,listener){
console.log(eventName);
console.log(listener);
});
emitter.addListener('say',hello);
//輸出say和[Function: hello]從上述的例子來(lái)看,每當(dāng)添加新的事件,都會(huì)自動(dòng)的emit一個(gè)“newListener”事件,且參數(shù)為eventName(新事件的名)和listener(新事件的執(zhí)行函數(shù))。
同理特殊事件removeListener也是同樣的,當(dāng)事件被移除,會(huì)自動(dòng)emit一個(gè)"removeListener"事件。
EventEmitter模塊的異常處理
(1) node中的try catch異常處理方法
在node中也可以通過(guò)try catch方式來(lái)捕獲和處理異常,比如:
try {
let x=x;
} catch (e) {
console.log(e);
}上述let x=x 賦值語(yǔ)句的錯(cuò)誤會(huì)被捕獲。這里提異常處理,那么跟事件有什么關(guān)系呢?
node中有一個(gè)特殊的事件error,如果異常沒(méi)有被捕獲,就會(huì)觸發(fā)process的uncaughtException事件拋出,如果你沒(méi)有注冊(cè)該事件的監(jiān)聽(tīng)器(即該事件沒(méi)有被處理),則 Node.js 會(huì)在控制臺(tái)打印該異常的堆棧信息,并結(jié)束進(jìn)程。
比如:
var events=require('events');
var emitter=new events.EventEmitter();
emitter.emit('error');在上述代碼中沒(méi)有監(jiān)聽(tīng)error的事件函數(shù),因此會(huì)觸發(fā)process的uncaughtException事件,從而打印異常堆棧信息,并結(jié)束進(jìn)程。
對(duì)于阻塞或者說(shuō)非異步的異常捕獲,try catch是沒(méi)有問(wèn)題的,但是:
try catch不能捕獲非阻塞或者異步函數(shù)里面的異常。
舉例來(lái)說(shuō):
try {
let x=x;//第二個(gè)x在使用前未定義,會(huì)拋出異常
} catch (e) {
console.log('該異常已經(jīng)被捕獲');
console.log(e);
}上述代碼中,以為try方法里面是同步的,因此可以捕獲異常。如果try方法里面有異步的函數(shù):
try {
process.nextTick(function(){
let x=x; //第二個(gè)x在使用前未定義,會(huì)拋出異常
});
} catch (e) {
console.log('該異常已經(jīng)被捕獲');
console.log(e);
}因?yàn)閜rocess.nextTick是異步的,因此在process.nextTick內(nèi)部的錯(cuò)誤不能被捕獲,也就是說(shuō)try catch不能捕獲非阻塞函數(shù)內(nèi)的異常。
(2) 通過(guò)domains管理異常
node中domain模塊能被用來(lái)集中地處理多個(gè)異常操作,通過(guò)node的domain模塊可以捕獲非阻塞函數(shù)內(nèi)的異常。
var domain=require('domain');
var eventDomain=domain.create();
eventDomain.on('error',function(err){
console.log('該異常已經(jīng)被捕獲了');
console.log(err);
});
eventDomain.run(function(){
process.nextTick(function(){
let x=x;//拋出異常
});
});同樣的,即使process.nextTick是一個(gè)異步函數(shù),domain.on方法也可以捕獲這個(gè)異步函數(shù)中的異常。
即使更復(fù)雜的情況下,比如異步嵌套異步的情況下,domain.on方法也可以捕獲異常。
var domain=require('domain');
var eventDomain=domain.create();
eventDomain.on('error',function(err){
console.log('該異常已經(jīng)被捕獲了');
console.log(err);
});
eventDomain.run(function(){
process.nextTick(function(){
setTimeout(function(){
setTimeout(function(){
let x=x;
},0);
},0);
});
});在上述的情況下,即使異步嵌套很復(fù)雜,也能在最外層捕獲到異常。
(3) domain模塊缺陷
在node最新的文檔中,domain被廢除(被標(biāo)記為:Deprecated),domain從誕生之日起就有著缺陷,舉例來(lái)說(shuō):
var domain = require('domain');
var EventEmitter = require('events').EventEmitter;
var e = new EventEmitter();
var timer = setTimeout(function () {
e.emit('data');
}, 10);
function next() {
e.once('data', function () {
throw new Error('something wrong here');
});
}
var d = domain.create();
d.on('error', function () {
console.log('cache by domain');
});
d.run(next);如上述的代碼是無(wú)法捕獲到異常Error的,原因在于發(fā)出異常的EventEmitter實(shí)例e,以及觸發(fā)異常的定時(shí)函數(shù)timer沒(méi)有被domain包裹。domain模塊是通過(guò)重寫(xiě)事件循環(huán)中的nextTick和_tickCallback來(lái)事件將process.domain注入到next包裹的所有異步事件內(nèi)。
解決上述無(wú)法捕獲異常的情況,只需要將e或者timer包裹進(jìn)domain。
d.add(e)或者d.add(timer)
就可以成功的捕獲異常。
domain模塊已經(jīng)在node最新的文檔中被廢除
(4)process.on('uncaughtException')的方法捕獲異常
node中提供了一個(gè)最外層的兜底的捕獲異常的方法。非阻塞或者異步函數(shù)中的異常都會(huì)拋出到最外層,如果異常沒(méi)有被捕獲,那么會(huì)暴露出來(lái),被最外層的process.on('uncaughtException')所捕獲。
try {
process.nextTick(function(){
let x=x; //第二個(gè)x在使用前未定義,會(huì)拋出異常
},0);
} catch (e) {
console.log('該異常已經(jīng)被捕獲');
console.log(e);
}
process.on('uncaughtException',function(err){console.log(err)})這樣就能在最外層捕獲異步或者說(shuō)非阻塞函數(shù)中的異常。
完整的實(shí)現(xiàn)一個(gè)EventEmitter模塊(可選讀)
在第二節(jié)中我們知道了EventEmitter模塊的基本用法,那么根據(jù)基本的API我們可以進(jìn)一步自己去實(shí)現(xiàn)一個(gè)EventEmitter模塊。
每一個(gè)EventEmitter實(shí)例都有一個(gè)包含所有事件的對(duì)象_events,
事件的監(jiān)聽(tīng)和監(jiān)聽(tīng)事件的觸發(fā),以及監(jiān)聽(tīng)事件的移除等都在這個(gè)對(duì)象_events的基礎(chǔ)上實(shí)現(xiàn)。
(1) emit
emit的方法實(shí)現(xiàn)的大致功能如下程序流程圖所示:

從上述的程序圖出發(fā),我們開(kāi)始實(shí)現(xiàn)自己的EventEmitter模塊。
首先生成一個(gè)EventEmitter類(lèi),在類(lèi)的初始化方法中生成這個(gè)事件對(duì)象_events.
class EventEmitter{
constructor(){
if(this._events===undefined){
this._events=Object.create(null);//定義事件對(duì)象
this._eventsCount=0;
}
}
}_eventsCount用于統(tǒng)計(jì)事件的個(gè)數(shù),也就是_events對(duì)象有多少個(gè)屬性。
接著我們來(lái)實(shí)現(xiàn)emit方法,根據(jù)框圖,我們知道emit所做的事情是在_events對(duì)象中取出相應(yīng)type的屬性,并執(zhí)行屬性所對(duì)應(yīng)的函數(shù),我們來(lái)實(shí)現(xiàn)這個(gè)emit方法。
class EventEmitter{
constructor(){
if(this._events===undefined){
this._events=Object.create(null);//定義事件對(duì)象
this._eventsCount=0;
}
}
emit(type,...args){
const events=this._events;
const handler=events[type];
//判斷相應(yīng)type的執(zhí)行函數(shù)是否為一個(gè)函數(shù)還是一個(gè)數(shù)組
if(typeof handler==='function'){
Reflect.apply(handler,this,args);
}else{
const len=handler.length;
for(var i=0;li<len;i++){
Reflect.apply(handler[i],this,args);
}
}
return true;
}
}(2) on、addListener和prependListener方法
emit方法是出發(fā)事件,并執(zhí)行相應(yīng)的方法,而on方法則是對(duì)于指定的事件添加監(jiān)聽(tīng)函數(shù)。用程序來(lái)說(shuō),就是往事件對(duì)象中_events添加相應(yīng)的屬性.程序流程圖如下所示:

接著我們來(lái)實(shí)現(xiàn)這個(gè)方法:
on(type,listener,prepend){
var m;
var events;
var existing;
events=this._events;
//添加事件的
if(events.newListener!==undefined){
this.emit('newListener',type,listener);
events=target._events;
}
existing=events[type];
//判斷相應(yīng)的type的方法是否存在
if(existing===undefined){
//如果相應(yīng)的type的方法不存在,這新增一個(gè)相應(yīng)type的事件
existing=events[type]=listener;
++this._eventsCount;
}else{
//如果存在相應(yīng)的type的方法,判斷相應(yīng)的type的方法是一個(gè)數(shù)組還是僅僅只是一個(gè)方法
//如果僅僅是
if(typeof existing==='function'){
//如果僅僅是一個(gè)方法,則添加
existing=events[type]=prepend?[listener,existing]:[existing,listener];
}else if(prepend){
existing.unshift(listener);
}else{
existing.push(listener);
}
}
//鏈?zhǔn)秸{(diào)用
return this;
}- 在on方法中為了可以鏈?zhǔn)降恼{(diào)用我們返回了EventEmitter模塊的實(shí)例化本身。
- 且在on方法的參數(shù)中,第三個(gè)參數(shù)用于指定是在相應(yīng)事件類(lèi)型屬性所對(duì)應(yīng)的數(shù)組頭部添加還是尾部添加,不傳的情況下實(shí)在尾部添加,如果指定prepend為true,則相同事件類(lèi)型的新的監(jiān)聽(tīng)事件會(huì)添加到事件數(shù)組的頭部。
- 如果_events存在newListener屬性,也就是說(shuō)_event存在監(jiān)聽(tīng)newListener監(jiān)聽(tīng)事件,那么每次on方法添加事件的時(shí)候,都會(huì)emit出一個(gè)‘newListener’方法。
在on方法的基礎(chǔ)上可以實(shí)現(xiàn)addListener方法和prependListener方法。
addListener方法是on方法的別名:
EventEmitter.prototype.addListener=EventEmitter.prototype.on
prependListener方法相當(dāng)于在頭部添加,指定prepend為true:
EventEmitter.prototype.prependListener =
function prependListener(type, listener) {
return EventEmitter.prototype.on(type, listener, true);
};(3) removeListener和removeAllListeners
接著來(lái)看移除事件監(jiān)聽(tīng)的方法removeListener和removeAllListeners,下面我們來(lái)看removeListener的程序流程圖:

接著來(lái)看removeListener的代碼:
removeListener(type,listener){
var list,events,position,i,originalListener;
events=this._events;
list=events[type];
//如果相應(yīng)的事件對(duì)象的屬性值是一個(gè)函數(shù),也就是說(shuō)事件只被一個(gè)函數(shù)監(jiān)聽(tīng)
if(list===listener){
if(--this._eventsCount===0){
this._events=Object.create(null);
}else{
delete events[type];
//如果存在對(duì)移除事件removeListener的監(jiān)聽(tīng)函數(shù),則觸發(fā)removeListener
if(events.removeListener)
this.emit('removeListener',type,listener);
}
}else if(typeof list!=='function'){
//如果相應(yīng)的事件對(duì)象屬性值是一個(gè)函數(shù)數(shù)組
//遍歷這個(gè)數(shù)組,找出listener對(duì)應(yīng)的那個(gè)函數(shù),在數(shù)組中的位置
for(i=list.length-1;i>=0;i--){
if(list[i]===listener){
position=i;
break;
}
}
//沒(méi)有找到這個(gè)函數(shù),則返回不做任何改動(dòng)的對(duì)象
if(position){
return this;
}
//如果數(shù)組的第一個(gè)函數(shù)才是所需要?jiǎng)h除的對(duì)應(yīng)listener函數(shù),則直接移除
if(position===0){
list.shift();
}else{
list.splice(position,1);
}
if(list.length===1)
events[type]=list[0];
if(events.removeListener!==undefined)
this.emit('removeListener',type,listener);
}
return this;
}- 如果在之間設(shè)置了對(duì)于移除這個(gè)特殊事件“removeListener”的監(jiān)聽(tīng),那么就會(huì)在移除事件時(shí)候觸發(fā)“removeListener”事件。
最后來(lái)看removeAllListener,這個(gè)與removeListener相似,只要找到傳入的type所對(duì)應(yīng)屬性的值,沒(méi)有遍歷過(guò)程,直接刪除這個(gè)屬性即可。
除此之外,還有其他的類(lèi)似與once、setMaxListeners、listeners也可以在此基礎(chǔ)上實(shí)現(xiàn),就不一一舉例。
總結(jié)
本文從node的EventEmitter模塊的使用出發(fā),介紹了EventEmitter提供的常用API,然后介紹了node中基于EventEmitter的異常處理,最后自己實(shí)現(xiàn)了一個(gè)較為完整的EventEmitter模塊,希望能夠有所幫助,更多關(guān)于node EventEmitter模塊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Node.js原理阻塞和EventEmitter及其繼承的運(yùn)用實(shí)戰(zhàn)
- node.js如何自定義實(shí)現(xiàn)一個(gè)EventEmitter
- 從零開(kāi)始學(xué)習(xí)Node.js系列教程六:EventEmitter發(fā)送和接收事件的方法示例
- TypeScript實(shí)現(xiàn)類(lèi)型安全的EventEmitter
- 參考EventEmitter實(shí)現(xiàn)完整訂閱發(fā)布功能函數(shù)
- 參考?EventEmitter實(shí)現(xiàn)一個(gè)簡(jiǎn)單的訂閱發(fā)布功能函數(shù)
相關(guān)文章
簡(jiǎn)單談?wù)刵ode.js 版本控制 nvm和 n
大量開(kāi)發(fā)者的貢獻(xiàn)使Node版本的迭代速度很快,版本很多(橫跨0.6到0.11),所以升級(jí)Node版本就成為了一個(gè)問(wèn)題。目前有n和nvm這兩個(gè)工具可以對(duì)Node進(jìn)行無(wú)痛升級(jí),本文簡(jiǎn)單介紹一下二者的使用。2015-10-10
Express.js 全局錯(cuò)誤處理實(shí)現(xiàn)
本文主要介紹了Express.js 全局錯(cuò)誤處理實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
關(guān)于NodeJs和JAVA建立socket連接方式
這篇文章主要介紹了關(guān)于NodeJs和JAVA建立socket連接方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Node.js使用NodeMailer發(fā)送郵件實(shí)例代碼
本篇文章主要介紹了Node.js使用NodeMailer發(fā)送郵件實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
nodejs中轉(zhuǎn)換URL字符串與查詢字符串詳解
這篇文章主要介紹了nodejs中轉(zhuǎn)換URL字符串與查詢字符串詳解,需要的朋友可以參考下2014-11-11
node.js中跨域請(qǐng)求實(shí)現(xiàn)方法詳解
這篇文章主要介紹了node.js中跨域請(qǐng)求實(shí)現(xiàn)方法詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-12-12
爬蟲(chóng)利器Puppeteer實(shí)戰(zhàn)
本文詳細(xì)的介紹了什么是Puppeteer以及使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01
Node.js報(bào)錯(cuò)信息Error:?Cannot?find?module?'XXX'問(wèn)題及解
這篇文章主要介紹了Node.js報(bào)錯(cuò)信息Error:?Cannot?find?module?'XXX'問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10

