• 学习笔记—Node中的Events模块


    日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。


    Events模块

    参考官网 events 事件触发器 | Node.js

    Events 模块是Node最重要的模块,它提供了一个属性 EventEmitterEventEmitter 的核心是事件发射与事件监听器。

    Node中大部分的模块,都继承自 Events 模块。

    • Events 模块是Node对 发布订阅模式publish/subscribe)的实现。一个对象通过这个模块,向另一个对象传递消息。
    • 该模块通过 EventEmitter 属性,提供了一个构造函数。该构造函数的实例具有 on 方法,可以用来监听指定事件,并触发回调函数。
    • 任意对象都可以发布指定事件,被 EventEmitter 实例的on方法监听到。

    发布订阅模式

    关于 发布订阅模式 ,可以参考我之前的博客文章。

    关于 Events 中的发布订阅模式,我们要先清楚它的几个常用方法。

    • 订阅方法on 方法用来订阅事件,订阅是将方法对应成一种一对多的关系。
    • 发布方法emit 用来执行订阅的事件。
    • 取消订阅off 方法可以移除对应的事件监听。
    • 订阅一次once 绑定事件当执行后自动删除订阅的事件。

    on 和 emit

    on 方法的第一个参数用来设定类名,第二个参数也是一个函数,里面可以接收发布时传入的参数。

    emit 方法第一个参数是类名,之后的参数都是传入 on 方法函数中的参数。

    onemit 具体应用可以参考下面这个简单的Demo。

    const EventEmitter = require('events');
    // 自定义一个 构造函数
    function Cat() {}
    // 原型继承 需要通过实例来调用继承方法
    Object.setPrototypeOf(Cat.prototype, EventEmitter.prototype);
    let cat = new Cat();
    const sleep = (a, b) => {
        console.log(a, '睡');
    };
    const eat = (a, b) => {
        console.log(b, '吃');
    };
    cat.on('猫咪', sleep)
    cat.on('猫咪', eat)
    setTimeout(() => {
      	// 小胡子 吃
      	// 小胖仙 睡
        cat.emit('猫咪', '小胖仙', '小胡子')
    }, 1000);
    

    现在我们可以实现一套 onemit 方法。

    function EventEmitter() {
        this._event = {}
    }
    // on 方法
    EventEmitter.prototype.on = function (eventName, callBack) {
        if (!this._event) {
            this._event = {}
        }
        if (this._event[eventName]) {
            this._event[eventName].push(callBack) // 相当于 {eventName:[fn1,fn2]}
        } else {
            this._event[eventName] = [callBack]; // 相当于 {eventName:[fn1]}
        }
    
    }
    // emit 方法
    EventEmitter.prototype.emit = function (eventName, ...args) {
        this._event[eventName].forEach(fn => {
            fn(...args)
        });
    }
    

    off

    off 方法的第一个参数用来设定类名,第二个参数传入需要被移除的函数回调。

    // ...
    setTimeout(() => {
      	// 小胡子 吃
      	// 小胖仙 睡
        cat.emit('猫咪', '小胖仙', '小胡子')
      	cat.off('猫咪', sleep);
      	// 小胡子 吃
        cat.emit('猫咪', '小胖仙', '小胡子')
    }, 1000);
    

    这样我们可以大概判断出来,移除掉和我们传入函数相同的函数,我们很快想到 filter 方法。

    // off 方法
    EventEmitter.prototype.off = function (eventName, callBack) {
        if (this._event && this._event[eventName]) {
            this._event[eventName] = this._event[eventName].filter(
              fn => fn !== callBack && fn.c !== callBack // fn.c参考下面的once方法实现
            )
        }
    }
    

    once

    once 方法的第一个参数用来设定类名,第二个参数传入只需要执行一次的函数回调。

    // ...
    const demolition =() => {
        console.log('拆家');
    }
    cat.once('猫咪', demolition)
    setTimeout(() => {
      	// ...... 拆家
        cat.emit('猫咪', '小胖仙', '小胡子')
    }, 1000);
    

    这样我们可以根据之前实现的 onoff 来实现此方法。

    // once 方法
    EventEmitter.prototype.once = function (eventName, callBack) {
        const one = () => {
            callBack();
            this.off(eventName, one);
        }
        this.on(eventName, one);
    }
    

    看起来这个方法好像没有什么问题,执行起来也全都是正确的。

    但是在一种特殊情况下的时候,还是出现了错误。

    那种情况就是如果我们在执行 once 方法之前,就已经通过 off 方法将其移除了。

    我们实现的方法就不能实现这个需求了,所以我们还需要对 once 方法进行一些修改 off 方法已经处理过了)

    添加一个自定义属性,用来对函数进行 “缓存” 。

    EventEmitter.prototype.once = function (eventName, callBack) {
        const one = () => {
            // ...
        }
        one.c = callBack; // 自定义一个属性
        // ...
    }
    

    这样我们就实现了 once 方法。

    本篇文章由 莫小尚 创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
    您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。
    最后感谢您的支持!

  • 相关阅读:
    css移除a标签及map、area(图片热区映射)点击过后的边框
    PDA后台运行、安装程序
    如何通过.Net Compact Framework来获得应用程序的当前路径
    mysql 实现row_number,获取上一条,下一条
    关于神经网络算法的 Python例程
    C# Windows Service 用代码实现安装、运行和卸载服务的方法
    sql server 递归查询的使用
    sql server 行转列及列转行的使用
    数据库索引优化
    LiveCharts 提示框(DataTooltip)百分比一直为0.00%解决办法
  • 原文地址:https://www.cnblogs.com/moxiaoshang/p/15652805.html
Copyright © 2020-2023  润新知