zoukankan      html  css  js  c++  java
  • Node.js-Events 模块总结与源码解析

    Events

    描述

    • 大多数 Node.js API 采用异步事件驱动架构,这些对象都是EventEmitter类的实例(Emitter),通过触发命名事件(eventName or type)来调用函数(监听器,listener)
    • Emitter 触发事件时,可以向监听器函数传递任意数量的参数,所有注册到该事件上的监听器函数都会依次同步执行,函数的返回值会被忽略

    事件

    • 命名规范:驼峰式字符串及任何有效的 JavaScript 属性键

    error

    error 事件被视为特殊情况,如果没有注册监听器会导致抛出错误、打印堆栈跟踪并退出 Node.js 进程,应始终为 error 事件注册监听器

    errorMonitor

    • errorMonitor 事件注册的监听器不会消耗 error,如果没有为 error 事件注册监听器,依然会导致抛出错误、打印堆栈跟踪并退出 Node.js 进程。

      'use strict'
      const EventEmitter = require('events').EventEmitter;
      const ee = new EventEmitter({ captureRejections: true });
      ee.on(EventEmitter.errorMonitor, function () {
          console.log('ErrorMonitor, call first');
      })
      ee.on('error', () => {
          console.log('customer error listener');
      })
      ee.emit('error');
      

    newListener

    • 当有新的监听器被添加时,所有 Emitter 都会触发 'newListener' 事件。

    • 为该事件注册监听器相当于一个钩子函数,可以获取到事件的名称要添加的监听器的引用

      class MyEmitter extends EventEmitter {}
      
      const myEmitter = new MyEmitter();
      // 只处理一次,避免无限循环。
      myEmitter.once('newListener', (event, listener) => {
          console.log(`为${event}添加事件${listener}`)
      })
      

    removeListener

    • 当现有的监听器被移除时,所有 Emitter 都会触发 'removeListener' 事件。
    • 为该事件注册监听器相当于一个钩子函数,可以获取到事件的名称要添加的监听器的引用

    监听器

    this指向

    普通函数中的this是触发事件的Emitter,箭头函数中的this是{}

    const EventEmitter = require('events').EventEmitter;
    const ee = new EventEmitter();
    function f1() {
        console.log('run f1, this = ', this);
    }
    const f2 = () => {
        console.log('run arrow function, this = ', this);
    }
    ee.on('test', f1);
    ee.on('test', f2);
    ee.emit('test');
    

    异步监听器

    如果添加异步监听器,需要开启captureRejections 选项且实现captureRejectionSymbol方法

    const { EventEmitter, captureRejectionSymbol } = require('events');
    const ee = new EventEmitter({ captureRejections: true });
    // 3中方式获取 kRejection 的 Symbol 值
    ee[ee.constructor.captureRejectionSymbol] = function (err, event, ...args) {
        console.log('rejection happened for', event, 'with', err, ...args);
    }
    ee[EventEmitter.captureRejectionSymbol] = function (err, event, ...args) {
        console.log('rejection happened for', event, 'with', err, ...args);
    }
    ee[captureRejectionSymbol] = function (err, event, ...args) {
        console.log('rejection happened for', event, 'with', err, ...args);
    }
    async function f() {
        return Promise.reject('async rejection');
    }
    ee.on('test', f);
    ee.emit('test');
    

    文档中这句话没太明白

    The 'error' events that are generated by the captureRejections behavior do not have a catch handler to avoid infinite error loops: the recommendation is to not use async functions as 'error' event handlers.

    执行次数

    • 通过EventEmitter#on() 方式注册的监听器,每次触发命名事件都会执行

    • 通过EventEmitter#once() 方式注册的监听器,触发命名事件只会执行一次

      触发once事件时,先触发removeListener事件移除监听器,再调用执行。在removeListener监听器中可拿到 once 监听器,可多次执行

      const EventEmitter = require('events').EventEmitter;
      
      let ee = new EventEmitter()
      
      ee.once('test', () => console.log('test'))
      
      ee.on('removeListener', (eventName, listener) => {
          console.log(`eventName: ${eventName}`)
          listener() // 多次执行
          listener()
          listener()
      })
      
      ee.emit('test')
      // eventName: test
      // test
      // test
      // test
      // test
      

    源码 v16.10

    代码注释 https://github.com/lfp1024/node/blob/master/lib/events.js

    常量

    const kRejection = SymbolFor('nodejs.rejection');
    const kCapture = Symbol('kCapture'); 
    const kErrorMonitor = Symbol('events.errorMonitor');
    const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
    const kMaxEventTargetListenersWarned =
      Symbol('events.maxEventTargetListenersWarned');
    

    前缀 k 表示常量 (德语 konstant)

    构造函数

    function EventEmitter(opts) {
      EventEmitter.init.call(this, opts); // 使 init 方法中的 this 指向新创建的实例,而非 EventEmitter 本身
    }
    module.exports = EventEmitter;
    
    • opts

      captureRejections

      • 类型:Boolean
      • 描述:是否开启自动捕获异步监听器的 rejection
        • false「默认」不开启
        • true 开启

    静态属性

    captureRejectionSymbol

    用来自定义异步监听器 rejection 的处理方法

    EventEmitter.captureRejectionSymbol = kRejection;
    

    errorMonitor

    事件名称

    在该事件上注册的监听器,只监听error事件,且在常规error事件监听器调用之前被调用,不消耗 error

    EventEmitter.errorMonitor = kErrorMonitor;
    

    captureRejections

    是否自动捕获异步监听器的rejection

    ObjectDefineProperty(EventEmitter, 'captureRejections', {
        get() {
            return EventEmitter.prototype[kCapture]; // 返回原型上的 kCapture
        },
        set(value) {
            if (typeof value !== 'boolean') {
                throw new ERR_INVALID_ARG_TYPE('EventEmitter.captureRejections',
                                               'boolean', value);
            }
            EventEmitter.prototype[kCapture] = value; // 设置原型上的 kCapture
        },
        enumerable: true
    });
    

    defaultMaxListeners

    单个事件默认最大可注册监听器个数

    • 默认情况下,每个事件可以最多注册 10 个监听器
    • 可以使用 EventEmitter.defaultMaxListeners 属性改变所有 EventEmitter 实例的默认值(包括之前创建的)。 如果此值不是一个正数,则抛出 RangeError
    let defaultMaxListeners = 10;
    ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
        enumerable: true,
        get: function() {
            return defaultMaxListeners;
        },
        set: function(arg) {
            if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
                throw new ERR_OUT_OF_RANGE('defaultMaxListeners',
                                           'a non-negative number',
                                           arg);
            }
            defaultMaxListeners = arg;
        }
    });
    

    静态方法

    init

    实例初始化

    EventEmitter.init = function(opts) {
      // new EventEmitter(),在init方法执行之前,先创建了一个对象,this就指向该对象
      if (this._events === undefined ||
          this._events === ObjectGetPrototypeOf(this)._events) { // 避免给原型添加`_events`属性,导致所有实例共享
        this._events = ObjectCreate(null); // 纯粹的键值对存储对象,没有原型
        this._eventsCount = 0;
      }
    // 如果原型上有_maxListener则新实例继承(_events不可以继承,_maxListener可以继承)
      this._maxListeners = this._maxListeners || undefined;
    
      if (opts?.captureRejections) {
        if (typeof opts.captureRejections !== 'boolean') {
          throw new ERR_INVALID_ARG_TYPE('options.captureRejections',
                                         'boolean', opts.captureRejections);
        }
        this[kCapture] = Boolean(opts.captureRejections);
      } else {
        // Assigning the kCapture property directly saves an expensive
        // prototype lookup in a very sensitive hot path.
        this[kCapture] = EventEmitter.prototype[kCapture]; // 默认值「false」
      }
    };
    

    setMaxListeners

    EventEmitter.setMaxListeners = function(n = defaultMaxListeners, ...eventTargets) {
        if (typeof n !== 'number' || n < 0 || NumberIsNaN(n))
            throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
        if (eventTargets.length === 0) {
            defaultMaxListeners = n;
        } else {
            if (isEventTarget === undefined)
                isEventTarget = require('internal/event_target').isEventTarget;
    
            for (let i = 0; i < eventTargets.length; i++) {
                const target = eventTargets[i];
                if (isEventTarget(target)) {
                    target[kMaxEventTargetListeners] = n;
                    target[kMaxEventTargetListenersWarned] = false;
                } else if (typeof target.setMaxListeners === 'function') {
                    target.setMaxListeners(n);
                } else {
                    throw new ERR_INVALID_ARG_TYPE(
                        'eventTargets',
                        ['EventEmitter', 'EventTarget'],
                        target);
                }
            }
        }
    };
    

    示例

    const { EventEmitter } = require('events');
    
    const ee = new EventEmitter();
    console.log(ee.getMaxListeners());
    
    EventEmitter.setMaxListeners(5, ee) // 可以用其静态方法修改某个ee的最大监听器个数
    console.log(ee.getMaxListeners());
    

    原型属性

    Symbol('kCapture')

    在原型和实例上各有一份,节省到原型上查找的开销

    是否捕获异步监听器的rejection

    const kCapture = Symbol('kCapture'); 
    ObjectDefineProperty(EventEmitter.prototype, kCapture, {
        value: false,
        writable: true,
        enumerable: false
    });
    
    // 获取方式
    const ee = new EventEmitter();
    console.log('ee.kCapture = ', ee[Reflect.ownKeys(ee)[3]]); // false
    

    实例属性

    Symbol('kCapture')

    在原型和实例上各有一份,节省到原型上查找的开销

    是否捕获异步监听器的rejection

    // init 方法中
    // Assigning the kCapture property directly saves an expensive
    // prototype lookup in a very sensitive hot path.
    this[kCapture] = EventEmitter.prototype[kCapture]; // 默认值「false」
    

    _events

    保存 监听事件 和 注册在该事件上的监听器

    EventEmitter.prototype._events = undefined; 
    

    _eventsCount

    当前实例中监听事件的个数

    EventEmitter.prototype._eventsCount = 0; 
    

    _maxListeners

    当前实例单个事件最大可注册监听器个数

    EventEmitter.prototype._maxListeners = undefined; 
    

    实例方法

    添加

    on

    同 addListener

    EventEmitter.prototype.on = EventEmitter.prototype.addListener;
    
    addListener

    把监听器添加到指定事件监听器数组的末尾,多次添加相同的监听器会多次调用

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.addListener = function addListener(type, listener) {
        return _addListener(this, type, listener, false); // 原型上的方法提出去,将this传入即可
    };
    
    function _addListener(target, type, listener, prepend) {
        let m;
        let events;
        let existing;
    
        checkListener(listener); // 检测listener是否为function,否则抛异常
    
        events = target._events;
        if (events === undefined) { // 未初始化
            events = target._events = ObjectCreate(null);
            target._eventsCount = 0;
        } else {
            // To avoid recursion in the case that type === "newListener"! Before
            // adding it to the listeners, first emit "newListener".
            if (events.newListener !== undefined) { // 是否监听 `newListener` 事件,每次注册监听器都会触发,类似钩子
                target.emit('newListener', type,
                            listener.listener ? listener.listener : listener);
    
                // Re-assign `events` because a newListener handler could have caused the
                // this._events to be assigned to a new object
                events = target._events; // 重新赋值
            }
            existing = events[type];
        }
    
        if (existing === undefined) { // 之前没有监听该事件
            // Optimize the case of one listener. Don't need the extra array object.
            events[type] = listener; //events 和 target._events 指向同一个对象
            ++target._eventsCount;
        } else { // 之前已经监听该事件
            if (typeof existing === 'function') {
                // Adding the second element, need to change to array.
                existing = events[type] =
                    prepend ? [listener, existing] : [existing, listener];
                // If we've already got an array, just append.
            } else if (prepend) {
                existing.unshift(listener);
            } else {
                existing.push(listener);
            }
    
            // Check for listener leak 检测最大监听器个数
            m = _getMaxListeners(target);
            if (m > 0 && existing.length > m && !existing.warned) {
                existing.warned = true; // 是否多余?
                // No error code for this since it is a Warning
                // eslint-disable-next-line no-restricted-syntax
                const w = new Error('Possible EventEmitter memory leak detected. ' +
                                    `${existing.length} ${String(type)} listeners ` +
                                    `added to ${inspect(target, { depth: -1 })}. Use ` +
                                    'emitter.setMaxListeners() to increase limit');
                w.name = 'MaxListenersExceededWarning';
                w.emitter = target;
                w.type = type;
                w.count = existing.length;
                process.emitWarning(w); // 发出警告
            }
        }
        return target;
    }
    
    prependListener

    把监听器添加到指定事件的监听器数组开头

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.prependListener =  function prependListener(type, listener) {
        return _addListener(this, type, listener, true);
    };
    
    once

    添加单次监听器到指定事件的监听器数组末尾,触发的时候先移除再执行

    返回实例的引用,以便可以链式调用

    function onceWrapper() {
        if (!this.fired) {
            this.target.removeListener(this.type, this.wrapFn); // 先移除监听器「同步操作」
            this.fired = true; // 标记已触发,保证只调用一次。【移除监听器】和【保证只调用一次】是两个分开的逻辑
            if (arguments.length === 0) // 再调用监听器
                return this.listener.call(this.target);
            return this.listener.apply(this.target, arguments);
        }
    }
    
    function _onceWrap(target, type, listener) {
        const state = { fired: false, wrapFn: undefined, target, type, listener };
        const wrapped = onceWrapper.bind(state);
        wrapped.listener = listener; // 挂载原始监听器,一同传递给 removeListener 方法
        state.wrapFn = wrapped; // 挂载包裹后的监听器,用于移除
        return wrapped;
    }
    
    EventEmitter.prototype.once = function once(type, listener) {
        checkListener(listener);
    
        this.on(type, _onceWrap(this, type, listener)); // 通过 once 监听的事件获取监听器的方式为 listener.listener
        return this;
    };
    
    prependOnceListener

    添加单次监听器到指定事件的监听器数组开头

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) {
        checkListener(listener);
    
        this.prependListener(type, _onceWrap(this, type, listener));
        return this;
    };
    

    移除

    off

    同 removeListener

    EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
    
    removeListener

    从指定事件的监听器数组中移除指定的监听器

    在事件触发之后,最后一个监听器执行完成之前, 移除监听器不会影响已触发的监听器执行

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.removeListener = function removeListener(type, listener) {
        checkListener(listener);
    
        const events = this._events;
        if (events === undefined) // 未初始化
            return this;
    
        const list = events[type];
        if (list === undefined)
            return this;
        // 事件只有一个 listener,则会发生 list === listener( once 注册的listener 为 list.listener)
        if (list === listener || list.listener === listener) {
            if (--this._eventsCount === 0) // event实例只有一个监听事件
                this._events = ObjectCreate(null);
            else { // event实例有多个监听事件
                delete events[type]; // 先移除后触发
                if (events.removeListener) // 如果监听了 `removeListener` 事件,则触发,类似钩子
                    this.emit('removeListener', type, list.listener || listener);
            }
        } else if (typeof list !== 'function') { // events[type] 只可能是函数或数组类型,这里判断非函数,则为数组类型?
            let position = -1; // 利用 `-1` 这个标志
    
            for (let i = list.length - 1; i >= 0; i--) {
                if (list[i] === listener || list[i].listener === listener) {
                    position = i;
                    break;
                }
            }
    
            if (position < 0)
                return this;
    
            if (position === 0)
                list.shift();
            else {
                if (spliceOne === undefined)
                    spliceOne = require('internal/util').spliceOne; // 类似 Array#splice(),但是速度较快
                spliceOne(list, position);
            }
    
            if (list.length === 1)
                events[type] = list[0]; // 单个listener不用数组
    
            if (events.removeListener !== undefined)
                this.emit('removeListener', type, listener);
        }
    
        return this;
    };
    
    removeAllListeners

    移除所有监听器或指定事件的所有监听器

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
        const events = this._events;
        if (events === undefined) // 未初始化
            return this;
    
        // 逻辑1: 没有注册 removeListener 事件
        // Not listening for removeListener, no need to emit
        if (events.removeListener === undefined) {
            if (arguments.length === 0) { // 等价于没传参数,type === undefined,删除所有监听事件
                this._events = ObjectCreate(null);
                this._eventsCount = 0;
            } else if (events[type] !== undefined) {
                if (--this._eventsCount === 0) // event实例只有一个监听事件
                    this._events = ObjectCreate(null);
                else
                    delete events[type];
            }
            return this;
        }
        // 逻辑2: 注册了 removeListener 事件
        // Emit removeListener for all listeners on all events
        if (arguments.length === 0) { // 删除所有监听事件
            for (const key of ReflectOwnKeys(events)) { // 较 Object#keys(),Reflect#ownKeys() 包含 Symbol 值的属性名
                if (key === 'removeListener') continue; // 把其他事件删除后,再删除。如果先删除,后面的事件就走逻辑1了
                this.removeAllListeners(key); // 递归,走逻辑3,然后返回
            }
            this.removeAllListeners('removeListener'); // 递归,走逻辑3,然后返回
            this._events = ObjectCreate(null);
            this._eventsCount = 0;
            return this;
        }
        // 逻辑3: 真正删除事件监听器
        const listeners = events[type];
    
        if (typeof listeners === 'function') {
            this.removeListener(type, listeners);
        } else if (listeners !== undefined) {
            // LIFO order
            for (let i = listeners.length - 1; i >= 0; i--) {
                this.removeListener(type, listeners[i]);
            }
        }
    
        return this;
    };
    

    修改

    setMaxListeners

    修改当前 EventEmitter 实例单个事件最大监听器个数。设为 Infinity(或 0)表示不限制监听器的数量

    返回实例的引用,以便可以链式调用

    EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
        if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
            throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
        }
        this._maxListeners = n;
        return this;
    };
    
    getMaxListeners

    返回当前EventEmitter 实例单个事件最大监听器个数

    EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
        return _getMaxListeners(this); // 把 this(实例)传进去
    };
    
    function _getMaxListeners(that) {
        if (that._maxListeners === undefined)
            return EventEmitter.defaultMaxListeners;
        return that._maxListeners;
    }
    

    获取

    listeners

    返回一个数组,包含指定事件的所有监听器(拆包之后)

    function _listeners(target, type, unwrap) {
        const events = target._events;
    
        if (events === undefined)
            return [];
    
        const evlistener = events[type];
        if (evlistener === undefined)
            return [];
    
        if (typeof evlistener === 'function')
            return unwrap ? [evlistener.listener || evlistener] : [evlistener];
    
        return unwrap ?
            unwrapListeners(evlistener) : arrayClone(evlistener);
    }
    
    EventEmitter.prototype.listeners = function listeners(type) {
        return _listeners(this, type, true);
    };
    
    rawListeners

    返回一个数组,包含指定事件的所有(原始)监听器

    如果是通过 once 注册的监听器,则返回的是被包装(wrap)后的监听器

    EventEmitter.prototype.rawListeners = function rawListeners(type) {
        return _listeners(this, type, false);
    };
    
    listenerCount

    返回指定事件上注册的监听器个数

    EventEmitter.prototype.listenerCount = listenerCount; 
    function listenerCount(type) {
        const events = this._events;
    
        if (events !== undefined) {
            const evlistener = events[type];
    
            if (typeof evlistener === 'function') {
                return 1;
            } else if (evlistener !== undefined) {
                return evlistener.length;
            }
        }
    
        return 0;
    }
    
    eventNames

    返回一个数组,包含所有监听事件。元素类型为 String 或 Symbol

    EventEmitter.prototype.eventNames = function eventNames() { // 所有监听事件
        return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
    };
    

    触发

    emit

    触发指定事件并同步调用注册到该事件上的所有监听器

    如果事件有监听器,则返回 true,否则返回 false

    EventEmitter.prototype.emit = function emit(type, ...args) {
        let doError = (type === 'error'); // error 事件,特殊处理
    
        const events = this._events;
        if (events !== undefined) { // 有监听事件
            if (doError && events[kErrorMonitor] !== undefined) // 如果是 error 事件,且用户添加了 kErrorMonitor 监听器
                this.emit(kErrorMonitor, ...args);
            doError = (doError && events.error === undefined); // 如果是 error 事件,且没有对应的 handler
        } else if (!doError) // events === undefined && !doError => 未初始化且不是 error 事件,则返回 false
            return false;
    
        // 触发 error 事件且没有handler,抛出异常(参数中的error实例或自己生成的error)
        // If there is no 'error' event listener then throw.
        if (doError) {
            // 1. 有监听事件 && 触发error事件 && 没有error事件的 handler
            // 2. 未初始化(肯定也没有error事件的 handler) && 触发error事件
            let er;
            if (args.length > 0)
                er = args[0];
            if (er instanceof Error) { // 第一个入参是 Error 实例
                try { // 给 er 添加当前栈信息(emit部分)
                    const capture = {};
                    ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
                    ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
                        value: enhanceStackTrace.bind(this, er, capture),
                        configurable: true
                    });
                } catch {}
    
                // Note: The comments on the `throw` lines are intentional, they show
                // up in Node's output if this results in an unhandled exception.
                throw er; // Unhandled 'error' event
            }
    
            let stringifiedEr;
            const { inspect } = require('internal/util/inspect');
            try {
                stringifiedEr = inspect(er);
            } catch {
                stringifiedEr = er;
            }
    
            // At least give some kind of context to the user
            const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
            err.context = er;
            throw err; // Unhandled 'error' event
        }
    
        const handler = events[type];
    
        // 如果是 error 事件,至此一定有handler,如果是其他类型事件,仍然需要判断handler的存在性
        if (handler === undefined)
            return false;
        // 单个handler是函数,多个handler是数组
        if (typeof handler === 'function') {
            const result = handler.apply(this, args);  // 参见 https://github.com/nodejs/node/pull/38248
    
            // We check if result is undefined first because that
            // is the most common case so we do not pay any perf
            // penalty
            if (result !== undefined && result !== null) {
                addCatch(this, result, type, args); // 如果是handler是异步函数,捕获其rejection异常
            }
        } else {
            const len = handler.length; // 确定监听器的个数,避免监听器中再监听同一个事件造成死循环
            const listeners = arrayClone(handler); // 克隆handler数组,防止在事件触发后,已注册监听器的变动
            for (let i = 0; i < len; ++i) {
                const result = listeners[i].apply(this, args); // 同步依次调用
    
                // We check if result is undefined first because that
                // is the most common case so we do not pay any perf
                // penalty.
                // This code is duplicated because extracting it away
                // would make it non-inlineable.
                if (result !== undefined && result !== null) {
                    addCatch(this, result, type, args);
                }
            }
        }
    
        return true;
    };
    
    function addCatch(that, promise, type, args) {
        if (!that[kCapture]) {
            return;
        }
        // 符合 Promises/A+ 规范的 promise 的属性 then 可能具有 get 方法,二次调用可能会报错,因此采用call方式
        // 因此下面采用的是 call 方式调用
        // Handle Promises/A+ spec, then could be a getter
        // that throws on second use.
        try {
            const then = promise.then;
    
            if (typeof then === 'function') {
                then.call(promise, undefined, function(err) {
                    // The callback is called with nextTick to avoid a follow-up // follow-up rejection ?
                    // rejection from this promise.
                    process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args);
                });
            }
        } catch (err) {
            that.emit('error', err);
        }
    }
    
    function emitUnhandledRejectionOrErr(ee, err, type, args) {
        if (typeof ee[kRejection] === 'function') { // 实例(用户)自己实现了 kRejection 函数
            ee[kRejection](err, type, ...args);
        } else {
            // We have to disable the capture rejections mechanism, otherwise
            // we might end up in an infinite loop.
    
            // 防止 error 事件 handler 也抛出 error,导致死循环。
            // 先保存之前的值,再关闭,如果程序未「退出」再恢复之前的值
            const prev = ee[kCapture];
    
            // If the error handler throws, it is not catcheable and it
            // will end up in 'uncaughtException'. We restore the previous
            // value of kCapture in case the uncaughtException is present
            // and the exception is handled.
            
            // 如果没有自定义 rejected promise 的处理函数,则走 error 事件的处理函数
            // 如果 error 事件 handler 也抛出 error,则不会被捕获,nodejs 会触发 uncaughtException 事件并「退出」
            // 如果用户处理了 uncaughtException 事件(通过 process#on() 处理),则恢复 kRejection 的值
            try {
                ee[kCapture] = false;
                ee.emit('error', err);
            } finally {
                ee[kCapture] = prev;
            }
        }
    }
    

    其他

    primordials

    primordials对象用来保证内建模块可以访问真正的不受用户干扰的全局变量

    https://stackoverflow.com/a/60215269/11089100

    spliceOne

    更高效的移除数组中的元素

    function spliceOne(list, index) {
      for (; index + 1 < list.length; index++)
        list[index] = list[index + 1]; // 从被移除元素开始,将后面的元素值依次向前复制
      list.pop(); // 移除最后一个元素
    }
    

    创建实例未初始化

    'use strict';
    
    const { EventEmitter, captureRejectionSymbol } = require('events');
    
    function MyEventEmitter() {
        // EventEmitter.call(this);
    }
    
    MyEventEmitter.prototype = EventEmitter.prototype;
    MyEventEmitter.prototype.constructor = MyEventEmitter
    
    const ee = new MyEventEmitter();
    
    // 上述创建 EventEmitter 实例的方式并没有调用 EventEmitter.init() 初始化,因此实例属性值都是 undefined
    console.log('ee._events = ', ee._events);
    console.log('ee._eventsCount = ', ee._eventsCount);
    ee.on('test', () => { console.log('tttttttt') });
    ee.emit('test');
    console.log('ee.eventNames = ',ee.eventNames());
    

    参考

    通过源码解析 Node.js 中 events 模块里的优化小细节

    通过源码分析nodejs原理

    中文文档

  • 相关阅读:
    《Effective Java》 读书笔记(三) 使用私有构造方法或枚举实现单例类
    《Effective Java》 读书笔记(二) 在构造参数过多的时候优先考虑使用构造器
    读书笔记-《Maven实战》-2018/5/3
    读书笔记-《Maven实战》-关于Maven依赖传递的思考 2018/4/26
    MySQL基础篇(07):用户和权限管理,日志体系简介
    SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级
    MySQL基础篇(06):事务管理,锁机制案例详解
    Java并发编程(02):线程核心机制,基础概念扩展
    SpringBoot2 整合ElasticJob框架,定制化管理流程
    Java基础篇(02):特殊的String类,和相关扩展API
  • 原文地址:https://www.cnblogs.com/usmile/p/14794853.html
Copyright © 2011-2022 走看看