最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解如何模擬實(shí)現(xiàn)node中的Events模塊(通俗易懂版)

 更新時(shí)間:2019年04月15日 12:02:39   作者:arzh  
這篇文章主要介紹了如何模擬實(shí)現(xiàn)node中的Events模塊(通俗易懂版),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Nodejs 的大部分核心 API 都是基于異步事件驅(qū)動(dòng)設(shè)計(jì)的,事件驅(qū)動(dòng)核心是通過 node 中 Events 對(duì)象來實(shí)現(xiàn)事件的發(fā)送和監(jiān)聽回調(diào)綁定,我們常用的 stream 模塊也是依賴于 Events 模塊是來實(shí)現(xiàn)數(shù)據(jù)流之間的回調(diào)通知,如在數(shù)據(jù)到來時(shí)觸發(fā) data 事件,流對(duì)象為可讀狀態(tài)觸發(fā) readable 事件,當(dāng)數(shù)據(jù)讀寫完畢后發(fā)送 end 事件。

既然 Events 模塊如此重要,我們有必要來學(xué)習(xí)一下 Events 模塊的基本使用,以及如何模擬實(shí)現(xiàn) Events 模塊中常用的 api

一、Events 模塊的基本使用以及簡單實(shí)現(xiàn)

首先我們了解一下 Events 模塊的基本用法,其實(shí) Events 模塊本質(zhì)上是觀察者模式的實(shí)現(xiàn),所謂觀察者模式就是:

它定義了對(duì)象間的一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知

觀察者模式有對(duì)應(yīng)的觀察者以及被觀察的對(duì)象,在 Events 模塊中,對(duì)應(yīng)的實(shí)現(xiàn)就是 on 和 emit 函數(shù)

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('嗨', (str) => {
 console.log(str);
});
myEmitter.emit('嗨','你好');

從上述的使用中,我們可以知道 on 是用來監(jiān)聽事件的發(fā)生,而 emit 是用來觸發(fā)事件的發(fā)生,一旦 emit 觸發(fā)了事件,on 就會(huì)被通知到,從而執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。

有了這個(gè)實(shí)例,我們可以思考下如何實(shí)現(xiàn)這個(gè) EventEmitter 類。

思路:當(dāng)我們執(zhí)行 on 函數(shù)時(shí),我們可以將回調(diào)函數(shù)保存起來,等到 emit 觸發(fā)了事件時(shí),將回調(diào)函數(shù)拿出來執(zhí)行,那么就可以實(shí)現(xiàn)了事件的監(jiān)聽以及訂閱了。

class EventEmitter{
 constructor(){
  #事件監(jiān)聽函數(shù)保存的地方
  this.events={};
 }
 on(eventName,listener){
  if (this.events[eventName]) {
   this.events[eventName].push(listener);
  } else {
   #如果沒有保存過,將回調(diào)函數(shù)保存為數(shù)組
   this.events[eventName] = [listener];
  }
 }
 emit(eventName){
  #emit觸發(fā)事件,把回調(diào)函數(shù)拉出來執(zhí)行
  this.events[eventName] && this.events[eventName].forEach(listener => listener())
 }
}

上述就實(shí)現(xiàn)了一個(gè)簡單的 EventEmitter 類,下面來實(shí)例一下:

let event = new EventEmitter();
event.on('嗨',function(){
 console.log('你好');
});
event.emit('嗨');
#輸出:你好

完善:我們注意到在原生的 EventEmitter 類中,emit 是可以傳遞參數(shù)到我們的回調(diào)函數(shù)中,那么我們實(shí)現(xiàn)的類也應(yīng)該支持傳遞參數(shù)。我們對(duì) emit 進(jìn)行如下更改

emit(eventName,...rest){
 #emit觸發(fā)事件,把回調(diào)函數(shù)拉出來執(zhí)行
 this.events[eventName] && this.events[eventName].forEach(listener => listener.apply(this,rest))
}

完善之后,重新實(shí)例化,如下:

let event = new EventEmitter();
event.on('嗨',function(str){
 console.log(str);
});
event.emit('嗨','你好');
#輸出:你好

二、Events 模塊中常用的 api

Events 模塊中除了 on、emit 函數(shù)之外,還包含了很多常用的 api,我們一一來介紹幾個(gè)實(shí)用的 api

API名稱 API方法描述
addListener(eventName, listener) on(eventName, listener)別名,為指定事件添加一個(gè)監(jiān)聽器到監(jiān)聽器數(shù)組的尾部
removeListener(eventName, listener) 從名為 eventName 的事件的監(jiān)聽器數(shù)組中移除指定的 listener
removeAllListeners(eventName, listener) 移除全部監(jiān)聽器或指定的 eventName 事件的監(jiān)聽器
once(eventName, listener) 添加單次監(jiān)聽器 listener 到名為 eventName 的事件
listeners(eventName) 返回名為 eventName 的事件的監(jiān)聽器數(shù)組的副本
setMaxListeners(n) 可以為指定的 EventEmitter 實(shí)例修改監(jiān)聽器數(shù)量限制

1. addListener 與 on 方法使用與實(shí)現(xiàn)

在 Events 模塊中,addListener 與 on 方法的使用是完成相同的,只是名字不同,我們可以通過原型來給兩個(gè)函數(shù)建立相等關(guān)聯(lián)

EventEmitter.prototype.addListener=EventEmitter.prototype.on

2. removeListener 與 off 方法使用與實(shí)現(xiàn)

removeListener 方法可以從指定名字的監(jiān)聽器數(shù)組中移除指定的 listener,這樣的話,當(dāng)再次 emit 事件的時(shí)候,不會(huì)觸發(fā) on 綁定的回調(diào)函數(shù),如下:

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let callback = (str) => {
 console.log(str);
}
myEmitter.on('嗨', callback);
myEmitter.emit('嗨','你好');#輸出:你好
myEmitter.removeListener('嗨',callback);
myEmitter.emit('嗨','你好');#無輸出

實(shí)現(xiàn)思路:我們只要在執(zhí)行 removeListener 函數(shù)的時(shí)候,將先前保存的回調(diào)函數(shù)去除掉即可

removeListener (eventName,listener) {
 #保證回調(diào)函數(shù)數(shù)組存在,同時(shí)去除指定的listener
 this.events[eventName] && this.events[eventName] = this.events[eventName].filter(l => l != listener);
}

同時(shí) removeListener 與 off 方法也是功能完全相同,只是命名不同,因此可以通過如下方法賦值:

EventEmitter.prototype.removeListener=EventEmitter.prototype.off

3. removeAllListeners 方法使用與實(shí)現(xiàn)

removeAllListeners 移除全部監(jiān)聽器或指定的 eventName 事件的監(jiān)聽器,其實(shí) removeAllListeners 就包含了 removeListener 的功能,只是 removeListener 只能指定特定的監(jiān)聽器,removeAllListeners 可以移除全部監(jiān)聽器。

實(shí)現(xiàn)思路:在執(zhí)行 removeAllListeners,將所有的回調(diào)函數(shù)都給去除即可

removeAllListeners (eventName) {
 #移除全部監(jiān)聽器
 delete this.events[eventName]
}

4. once 方法使用與實(shí)現(xiàn)

once 方法的描述是添加單次監(jiān)聽器 listener 到名為 eventName 的事件,其實(shí)就是通過 once 添加的監(jiān)聽器,只能執(zhí)行一次,執(zhí)行一次之后就會(huì)被銷毀,不能再次執(zhí)行

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.once('嗨', (str) => {
 console.log(str);
});
myEmitter.emit('嗨','你好');
myEmitter.emit('嗨','你好');
myEmitter.emit('嗨','你好'); #只能輸出一次你好

實(shí)現(xiàn)思路:當(dāng) once 監(jiān)聽的事件回調(diào)函數(shù)執(zhí)行之后,通過 removeListener 將事件監(jiān)聽器給解綁掉,那么事件再次被 emit 的時(shí)候,就不會(huì)再次執(zhí)行回調(diào),這樣就能保證事件回調(diào)只能執(zhí)行一次

once (eventName, listener) {
 #重新改變監(jiān)聽回調(diào)函數(shù),使其執(zhí)行之后可以被銷毀
 let reListener = (...rest) => {
  listener.apply(this,rest);
  #執(zhí)行完之后解除事件綁定
  this.removeListener(type,wrapper);
 }
 this.on(eventName,reListener);
}

5. listeners 方法使用與實(shí)現(xiàn)

listeners 方法返回名為 eventName 的事件的監(jiān)聽器數(shù)組的副本,其實(shí)就是獲取 eventName 中所有的回調(diào)函數(shù),這個(gè)實(shí)現(xiàn)起來很容易,就不多贅述了,代碼如下:

listeners (eventName) {
 return this.events[eventName]
}

6. setMaxListeners 方法使用與實(shí)現(xiàn)

默認(rèn)情況下,如果為特定事件添加了超過 10 個(gè)監(jiān)聽器,則 EventEmitter 會(huì)打印一個(gè)警告。 這有助于發(fā)現(xiàn)內(nèi)存泄露, 但是,并不是所有的事件都要限制 10 個(gè)監(jiān)聽器。 emitter.setMaxListeners() 方法可以為指定的 EventEmitter 實(shí)例修改限制。 值設(shè)為 Infinity(或 0)表示不限制監(jiān)聽器的數(shù)量。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let callback = (str) => {
 console.log(str);
}
for (let i = 0; i <= 11; i++) {
 myEmitter.on('嗨', callback);
}
myEmitter.emit('嗨', '你好');

輸入結(jié)果如圖:

實(shí)現(xiàn)思路:

我們先將特定事件的監(jiān)聽器最大設(shè)置為常量10

constructor(){
 #事件監(jiān)聽函數(shù)保存的地方
 this.events={};
 #最大監(jiān)聽器數(shù)量
 this._maxListeners = 10;
}

然后在我們的 on 函數(shù)中,對(duì)這個(gè)監(jiān)聽器的數(shù)量進(jìn)行判斷,從而作出提示

on(eventName,listener){
 if (this.events[eventName]) {
  this.events[eventName].push(listener);
  #如果超過最大限度,以及不為0,則作出內(nèi)存泄漏提示
  if (this._maxListeners != 0 && this.events[type].length >= this._maxListeners) {
   console.error('超過最大的監(jiān)聽數(shù)量可能會(huì)導(dǎo)致內(nèi)存泄漏');
  }
 } else {
  #如果沒有保存過,將回調(diào)函數(shù)保存為數(shù)組
  this.events[eventName] = [listener];
 }
}

我們也支持對(duì) _maxListeners 變量根據(jù)用戶的輸入進(jìn)行更改,即我們的 setMaxListeners() 函數(shù)

setMaxListeners(MaxListeners) {
 this._maxListeners = MaxListeners
}

三、總結(jié)

本文從 node 的 Events 模塊出發(fā),然后去介紹了 Events 模塊常用 API 的使用,從中通過一步一步簡易去思考這些 API 使用的內(nèi)部原理,簡易的實(shí)現(xiàn)了這些 API,希望大家看完文章之后,能對(duì) Events 模塊有進(jìn)一步的理解。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Node.js基于cors解決接口跨域的問題(推薦)

    Node.js基于cors解決接口跨域的問題(推薦)

    這篇文章主要介紹了Node.js基于cors解決接口跨域的問題,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • node.js Sequelize實(shí)現(xiàn)單實(shí)例字段或批量自增、自減

    node.js Sequelize實(shí)現(xiàn)單實(shí)例字段或批量自增、自減

    Sequelize 可以實(shí)現(xiàn)針對(duì)單個(gè)實(shí)例的一或多個(gè)字段的自增、自減操作,也可以對(duì)符合條件的數(shù)據(jù)進(jìn)行批量的自增、自減操作。單個(gè)實(shí)例字段的自增、自減可以利用Instance的相應(yīng)方法實(shí)現(xiàn),而批量自增、自減則需要借助sequelize提供的字面量方法實(shí)現(xiàn)。下面來看看詳細(xì)的介紹吧。
    2016-12-12
  • Node.js Sequelize如何實(shí)現(xiàn)數(shù)據(jù)庫的讀寫分離

    Node.js Sequelize如何實(shí)現(xiàn)數(shù)據(jù)庫的讀寫分離

    Sequelize是一個(gè)易于使用,支持多SQL方言(dialect)的對(duì)象-關(guān)系映射框架(ORM),這個(gè)庫完全采用JavaScript開發(fā)并且能夠用在Node.JS環(huán)境中。它當(dāng)前支持MySQL, MariaDB, SQLite 和 PostgreSQL 數(shù)據(jù)庫。在Node.js中,使用 Sequelize操作數(shù)據(jù)庫時(shí),同樣支持讀寫分離。
    2016-10-10
  • Node.js實(shí)現(xiàn)mysql連接池使用事務(wù)自動(dòng)回收連接的方法示例

    Node.js實(shí)現(xiàn)mysql連接池使用事務(wù)自動(dòng)回收連接的方法示例

    這篇文章主要介紹了Node.js實(shí)現(xiàn)mysql連接池使用事務(wù)自動(dòng)回收連接的方法,結(jié)合實(shí)例形式分析了node.js操作mysql連接池實(shí)現(xiàn)基于事務(wù)的連接回收操作相關(guān)技巧,需要的朋友可以參考下
    2018-02-02
  • Node.js中的CommonJS模塊化規(guī)范詳解

    Node.js中的CommonJS模塊化規(guī)范詳解

    這篇文章主要介紹了Node.js中的CommonJS模塊化規(guī)范,本文主要介紹了?CommonJS?規(guī)范在?Node?中的簡單應(yīng)用,主要就是導(dǎo)入和導(dǎo)出模塊,需要的朋友可以參考下
    2023-02-02
  • npm?install常見報(bào)錯(cuò)以及問題詳解

    npm?install常見報(bào)錯(cuò)以及問題詳解

    npm?install總是一言難盡,下面這篇文章主要給大家介紹了關(guān)于npm?install常見報(bào)錯(cuò)以及問題的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • nodejs使用express創(chuàng)建一個(gè)簡單web應(yīng)用

    nodejs使用express創(chuàng)建一個(gè)簡單web應(yīng)用

    這篇文章主要介紹了nodejs使用express創(chuàng)建一個(gè)簡單web應(yīng)用的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Node.js使用MongoDB的ObjectId作為查詢條件的方法

    Node.js使用MongoDB的ObjectId作為查詢條件的方法

    這篇文章主要介紹了Node.js使用MongoDB的ObjectId作為查詢條件的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • NodeJs crypto加密制作token的實(shí)現(xiàn)代碼

    NodeJs crypto加密制作token的實(shí)現(xiàn)代碼

    這篇文章主要介紹了NodeJs crypto加密制作token的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • node.js文件上傳重命名以及移動(dòng)位置的示例代碼

    node.js文件上傳重命名以及移動(dòng)位置的示例代碼

    本篇文章主要介紹了node.js文件上傳重命名以及移動(dòng)位置的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01

最新評(píng)論

秦安县| 兴安县| 化德县| 新巴尔虎左旗| 华亭县| 农安县| 绥中县| 富阳市| 永泰县| 东光县| 民勤县| 凤凰县| 佛山市| 建瓯市| 孟连| 耿马| 百色市| 青州市| 丰原市| 福贡县| 屏南县| 阿图什市| 探索| 雷州市| 大名县| 韶山市| 高碑店市| 札达县| 武穴市| 靖江市| 宕昌县| 正镶白旗| 哈尔滨市| 聂荣县| 鹿泉市| 布拖县| 永吉县| 微山县| 施秉县| 丽水市| 郯城县|