国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入nodejs-核心模塊Events詳解(事件驅(qū)動(dòng))

hidogs / 1455人閱讀

摘要:實(shí)現(xiàn)方式其實(shí)就是對(duì)方法做了一層封裝,將一個(gè)封裝好的代替?zhèn)鬟f給方法內(nèi)部會(huì)執(zhí)行一次監(jiān)聽回調(diào)函數(shù),然后再調(diào)用對(duì)該回調(diào)進(jìn)行刪除。

事件驅(qū)動(dòng)
Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境。Node.js 使用了一個(gè)事件驅(qū)動(dòng)、非阻塞式 I/O的模型,使其輕量又高效。Allows you to build scalable network applications usingJavaScript on the server-side.

對(duì)于上面這段官方的引用大家應(yīng)該都看過,nodejs是基于事件驅(qū)動(dòng)和非阻塞I/O的方式來設(shè)計(jì)運(yùn)行的,那么作為實(shí)現(xiàn)事件驅(qū)動(dòng)的核心模塊Events就成了深入學(xué)習(xí)node.js的關(guān)鍵。在node中大部分的模塊的實(shí)現(xiàn)都繼承了Events類。 比如,文件操作中的fs事件流,網(wǎng)絡(luò)編程所用到的tcp,http模塊等,當(dāng)你回想自己寫的程序后,會(huì)發(fā)現(xiàn)很多操作都基于事件驅(qū)動(dòng),Events類。

那么問題是什么是事件驅(qū)動(dòng)呢?

簡(jiǎn)單來說,就是通過監(jiān)聽事件的狀態(tài)變化來做出相應(yīng)的操作。比如讀取一個(gè)文件,文件讀取完畢,或者文件讀取錯(cuò)誤,那么就觸發(fā)對(duì)應(yīng)的狀態(tài),然后調(diào)用對(duì)應(yīng)的回掉函數(shù)來進(jìn)行處理。

我們來簡(jiǎn)單的看幾段代碼來回憶一下:

    const fs = require("fs");
    
    let rs = fs.createReadStream("1.txt");
    
    // 監(jiān)聽文件打開操作
    rs.on("open", function() {
      console.log("open");
    });
    
    // 監(jiān)聽數(shù)據(jù)流讀取
    rs.on("data", function(data) {
      console.log(data);
    });
    
    // 監(jiān)聽錯(cuò)誤
    rs.on("error", function() {
      console.log("error");
    });
    
    // 監(jiān)聽讀取結(jié)束操作
    rs.on("end", function() {
      console.log("end");
    });
    
    
    // 監(jiān)聽文件關(guān)閉操作
    rs.on("close", function() {
      console.log("close");
    });

上面這段在創(chuàng)建文件讀取流的操作上,針對(duì)文件的打開,數(shù)據(jù),錯(cuò)誤,結(jié)束,關(guān)閉等幾個(gè)狀態(tài)進(jìn)行了監(jiān)聽的回調(diào)處理,這也應(yīng)征了我們上面的定義通過監(jiān)聽事件的狀態(tài)變化來做出相應(yīng)的操作。
那么這些監(jiān)聽事件又是如何觸發(fā)的呢?它是通過Events類中的emit方法去發(fā)射事件的。那么下面我們來看一下Events是如何實(shí)現(xiàn)這樣的監(jiān)聽操作的。

Events類 主要的幾個(gè)核心API

on(eventName, listener)和emitter.addListener(eventName, listener):對(duì)指定事件綁定事件處理函數(shù)

once(eventName, listener):對(duì)指定事件指定只執(zhí)行一次的事件處理函數(shù)

emit(eventName[, ...args]): 觸發(fā)指定事件

removeListener(eventName, listener):對(duì)指定事件解除事件處理函數(shù)

removeAllListeners([event]):對(duì)指定的事件接觸所有的事件處理函數(shù)

setMaxListeners 設(shè)置最大隊(duì)列的長(zhǎng)度

下面來看一下代碼,看看是怎么使用的

    const events = require("events");
    
    const EventsEmitter = new events();
    
    //===============事件監(jiān)聽部分===============
    EventsEmitter.on("open", function() {
      console.log("open");
    });
    
    EventsEmitter.on("data", function(data) {
      console.log(data);
    });
    
    EventsEmitter.on("error", function() {
      console.log("error");
    });
    
    EventsEmitter.on("end", function() {
      console.log("end");
    });
    
    EventsEmitter.on("close", function() {
      console.log("close");
    });
    
    //=============事件觸發(fā)部分=================
    
    // 觸發(fā)open事件
    EventsEmitter.emit("open");
    // 觸發(fā)data事件,并傳遞一個(gè)字符串參數(shù)"test"
    EventsEmitter.emit("data","test");
    // 觸發(fā)error事件
    EventsEmitter.emit("error");
    // 觸發(fā)end事件
    EventsEmitter.emit("end");
    // 觸發(fā)close事件
    EventsEmitter.emit("close");

看完上面這段代碼是不是更進(jìn)一步的理解了呢。我們回顧最最上面的那段文件流監(jiān)聽的代碼,其實(shí)就是文件在不同的狀態(tài)下去發(fā)射相應(yīng)的emit事件。 而在那段代碼中我們并沒有去引入events這個(gè)node提供的模塊,是因?yàn)槲募髦欣^承了events模塊,所以rs這個(gè)變量也就擁有了相應(yīng)的rs.on()這個(gè)方法了。

看到這里我想應(yīng)該都了解的差不多了。那么下面來試著實(shí)現(xiàn)一下Events這個(gè)類,加深理解。

初始化Events模塊

創(chuàng)建一個(gè)Events類

初始化this.events用來保存我們需要監(jiān)聽的事件

將模塊導(dǎo)出

class Events {
  constructor() {
    this.events = {};
  }
}

module.exports = Events;
實(shí)現(xiàn)Events.on方法

on方法接收兩個(gè)參數(shù):

type:監(jiān)聽的事件類型

listener:回調(diào)函數(shù)

將對(duì)應(yīng)的事件先存放在一個(gè)對(duì)象中,分兩種情況:

該事件對(duì)象不存在,那么以type為key,[listener]為值存放在實(shí)現(xiàn)初始化好的this.events對(duì)象中(注意這里存的是一個(gè)數(shù)組,例如data事件,this.events = {data:[callback]})

如果該事件已經(jīng)存在則直接push

監(jiān)聽函數(shù)就這么簡(jiǎn)單的實(shí)現(xiàn)了,接下來就是等著被emit觸發(fā)了。

  /**
   * 事件監(jiān)聽
   * @param {*} type        監(jiān)聽的事件類型
   * @param {*} listener    回調(diào)函數(shù)
   */
  on(type, listener) {
    if (this.events[type]) {
      this.events[type].push(listener);
    } else {
      this.events[type] = [listener];
    }
  }

這里在補(bǔ)充一下,同一個(gè)監(jiān)聽事件是可以添加多個(gè)的,所以這里才會(huì)this.events[type]才會(huì)給一個(gè)數(shù)組來存儲(chǔ)

實(shí)現(xiàn)Events.emit方法

接收兩個(gè)參數(shù):

type:要觸發(fā)的事件類型

...rest:若干個(gè)參數(shù),傳遞給對(duì)應(yīng)事件的回調(diào)函數(shù)

通過type,在this.events里找到相應(yīng)的事件,這里我們上面是存成了一個(gè)數(shù)組,里面對(duì)應(yīng)的是事件的回調(diào)好書。

循環(huán)數(shù)組,執(zhí)行所有對(duì)應(yīng)事件的回調(diào)。

  /**
   * 事件觸發(fā)
   * @param {*} type        要觸發(fā)的事件類型
   * @param  {...any} rest  接收到的若干個(gè)參數(shù),這個(gè)參數(shù)會(huì)作為參數(shù)被傳遞到對(duì)應(yīng)事件的回調(diào)函數(shù)中
   */
  emit(type, ...rest) {
    if (this.events[type]) {
      this.events[type].forEach(listener => {
        listener.apply(this, rest);
      });
    }
  }

寫到這里,我們之前的代碼就能夠引入自己寫的這個(gè)Events模塊來執(zhí)行了

實(shí)現(xiàn)Events.removeListener方法

這個(gè)方法是用來刪除對(duì)應(yīng)事件的某個(gè)監(jiān)聽函數(shù),那么我們只需要把該事件從this.events[type]中刪除即可

接收兩個(gè)參數(shù):

type:事件類型

listener:要?jiǎng)h除的監(jiān)聽函數(shù)

通過this.events[type]找到對(duì)應(yīng)的事件監(jiān)聽函數(shù)數(shù)組

通過filter對(duì)要?jiǎng)h除的監(jiān)聽函數(shù)進(jìn)行過濾

  /**
   * 刪除指定事件中的監(jiān)聽函數(shù)
   * @param {*} type      對(duì)應(yīng)的事件 
   * @param {*} listener  要?jiǎng)h除的監(jiān)聽函數(shù)
   */
  removeListener(type, listener) {
    if (this.events[type]) {
      this.events[type].filter(l => l !== listener);
    }
  }  
實(shí)現(xiàn)Events.once方法

這個(gè)方法和on一樣,唯一的區(qū)別就是它只會(huì)執(zhí)行一次,即便多次調(diào)用emit去觸發(fā)相同的事件監(jiān)聽,它也只會(huì)執(zhí)行一次。

實(shí)現(xiàn)方式其實(shí)就是對(duì)on()方法做了一層封裝,將一個(gè)封裝好的wraper代替listener傳遞給on()方法

wraper內(nèi)部會(huì)執(zhí)行一次監(jiān)聽回調(diào)函數(shù),然后再調(diào)用this.removeListern對(duì)該回調(diào)進(jìn)行刪除。

  /**
   * 事件監(jiān)聽,但是只執(zhí)行一次
   * @param {*} type        監(jiān)聽的事件類型
   * @param {*} listener    回調(diào)函數(shù)
   */
  once(type, listener) {
    const wraper = (...rest) => {
      listener.apply(this, rest);
      this.removeListener(type, wraper);
    };
    this.on(type, wrapper);
  }
完整代碼
class Events {
  constructor() {
    this.events = {};
  }
  /**
   * 事件監(jiān)聽
   * @param {*} type        監(jiān)聽的事件類型
   * @param {*} listener    回調(diào)函數(shù)
   */
  on(type, listener) {
    if (this.events[type]) {
      this.events[type].push(listener);
    } else {
      this.events[type] = [listener];
    }
  }

  /**
   * 事件監(jiān)聽,但是只執(zhí)行一次
   * @param {*} type        監(jiān)聽的事件類型
   * @param {*} listener    回調(diào)函數(shù)
   */
  once(type, listener) {
    const wraper = (...rest) => {
      listener.apply(this, rest);
      this.removeListener(type, wraper);
    };
    this.on(type, wrapper);
  }

  /**
   * 事件觸發(fā)
   * @param {*} type        要觸發(fā)的事件類型
   * @param  {...any} rest  接收到的若干個(gè)參數(shù),這個(gè)參數(shù)會(huì)作為參數(shù)被傳遞到對(duì)應(yīng)事件的回調(diào)函數(shù)中
   */
  emit(type, ...rest) {
    if (this.events[type]) {
      this.events[type].forEach(listener => {
        listener.apply(this, rest);
      });
    }
  }

  /**
   * 刪除指定事件中的監(jiān)聽函數(shù)
   * @param {*} type      對(duì)應(yīng)的事件
   * @param {*} listener  要?jiǎng)h除的監(jiān)聽函數(shù)
   */
  removeListener(type, listener) {
    if (this.events[type]) {
      this.events[type].filter(l => l !== listener);
    }
  }
}

module.exports = Events;
總結(jié)

Events模塊是node非常核心的模塊,它對(duì)你深入去學(xué)習(xí)node有很大的幫助,上面我只寫了幾個(gè)方法,內(nèi)部還有幾個(gè)API以及一些非常細(xì)節(jié)的地方可以自己試著去擴(kuò)展,我這里就不一個(gè)一個(gè)的去寫了,文章有寫不好的地方或者看不懂的地方都可以給我留言哦。

如果覺得寫的還行,方便的話幫忙點(diǎn)個(gè)贊哦,謝謝了。

以下我的新個(gè)人微信公眾號(hào),在里面也會(huì)為大家提供原創(chuàng)文章,歡迎大家關(guān)注,當(dāng)關(guān)注用戶量夠了,我會(huì)在里面推出一些視頻教程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108980.html

相關(guān)文章

  • 解析nodeJS模塊源碼 親手打造基于ES6的觀察者系統(tǒng)

    摘要:為指定事件注冊(cè)一個(gè)單次監(jiān)聽器,即監(jiān)聽器最多只會(huì)觸發(fā)一次,觸發(fā)后立刻解除該監(jiān)聽器。移除指定事件的某個(gè)監(jiān)聽器,監(jiān)聽器必須是該事件已經(jīng)注冊(cè)過的監(jiān)聽器。返回指定事件的監(jiān)聽器數(shù)組。如何創(chuàng)建空對(duì)象我們已經(jīng)了解到,是要來儲(chǔ)存監(jiān)聽事件監(jiān)聽器數(shù)組的。 毫無疑問,nodeJS改變了整個(gè)前端開發(fā)生態(tài)。本文通過分析nodeJS當(dāng)中events模塊源碼,由淺入深,動(dòng)手實(shí)現(xiàn)了屬于自己的ES6事件觀察者系統(tǒng)。千萬不...

    csRyan 評(píng)論0 收藏0
  • 深入淺出Node.js

    摘要:深入淺出一直想致力于寫一篇關(guān)于廣義講解系統(tǒng)的文章,苦于時(shí)間有限,資源有限。事件驅(qū)動(dòng)機(jī)制是通過內(nèi)部單線程高效率地維護(hù)事件循環(huán)隊(duì)列來實(shí)現(xiàn)的,沒有多線程的資源占用和上下文的切換。 深入淺出Node.js 一直想致力于寫一篇關(guān)于廣義講解Node.js系統(tǒng)的文章,苦于時(shí)間有限,資源有限。這篇文章是在結(jié)合自己的學(xué)習(xí)心得以及與行業(yè)大佬共同探討下爭(zhēng)對(duì)于熟練掌握J(rèn)S語言后的廣義Node.js.至于為什么...

    oujie 評(píng)論0 收藏0
  • 深入淺出Node.js

    摘要:深入淺出一直想致力于寫一篇關(guān)于廣義講解系統(tǒng)的文章,苦于時(shí)間有限,資源有限。事件驅(qū)動(dòng)機(jī)制是通過內(nèi)部單線程高效率地維護(hù)事件循環(huán)隊(duì)列來實(shí)現(xiàn)的,沒有多線程的資源占用和上下文的切換。 深入淺出Node.js 一直想致力于寫一篇關(guān)于廣義講解Node.js系統(tǒng)的文章,苦于時(shí)間有限,資源有限。這篇文章是在結(jié)合自己的學(xué)習(xí)心得以及與行業(yè)大佬共同探討下爭(zhēng)對(duì)于熟練掌握J(rèn)S語言后的廣義Node.js.至于為什么...

    MadPecker 評(píng)論0 收藏0
  • 深入淺出Node.js

    摘要:深入淺出一直想致力于寫一篇關(guān)于廣義講解系統(tǒng)的文章,苦于時(shí)間有限,資源有限。事件驅(qū)動(dòng)機(jī)制是通過內(nèi)部單線程高效率地維護(hù)事件循環(huán)隊(duì)列來實(shí)現(xiàn)的,沒有多線程的資源占用和上下文的切換。 深入淺出Node.js 一直想致力于寫一篇關(guān)于廣義講解Node.js系統(tǒng)的文章,苦于時(shí)間有限,資源有限。這篇文章是在結(jié)合自己的學(xué)習(xí)心得以及與行業(yè)大佬共同探討下爭(zhēng)對(duì)于熟練掌握J(rèn)S語言后的廣義Node.js.至于為什么...

    lily_wang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<