linfeimy / Node.js-Demo

Node.js相关学习记录
0 stars 0 forks source link

events模块 #7

Open linfeimy opened 5 years ago

linfeimy commented 5 years ago
console.log(process);
process {
    title: 'D:\\develop\\nodejs\\node.exe',
    version: 'v10.16.0',
    versions: {
        http_parser: '2.8.0',
        node: '10.16.0',
        v8: '6.8.275.32-node.52',
        uv: '1.28.0',
        zlib: '1.2.11',
        brotli: '1.0.7',
        ares: '1.15.0',
        modules: '64',
        nghttp2: '1.34.0',
        napi: '4',
        openssl: '1.1.1b',
        icu: '64.2',
        unicode: '12.1',
        cldr: '35.1',
        tz: '2019a'
    },
    arch: 'x64',
    platform: 'win32',
    release: {
        name: 'node',
        lts: 'Dubnium',
        sourceUrl: 'https://nodejs.org/download/release/v10.16.0/node-v10.16.0.tar.gz',
        headersUrl: 'https://nodejs.org/download/release/v10.16.0/node-v10.16.0-headers.tar.gz',
        libUrl: 'https://nodejs.org/download/release/v10.16.0/win-x64/node.lib'
    },
    argv: ['D:\\develop\\nodejs\\node.exe', 'E:\\linfeimy\\02personal\\Node.js-Demo\\Node.js v10.6.2\\events\\index.js'],
    execArgv: [],
    env: {
        ALLUSERSPROFILE: 'C:\\ProgramData',
        APPDATA: 'C:\\Users\\qian0\\AppData\\Roaming',
        'asl.log': 'Destination=file',
        COLORTERM: 'true',
        CommonProgramFiles: 'C:\\Program Files\\Common Files',
        'CommonProgramFiles(x86)': 'C:\\Program Files (x86)\\Common Files',
        CommonProgramW6432: 'C:\\Program Files\\Common Files',
        COMPUTERNAME: 'DESKTOP-O11HVTS',
        ComSpec: 'C:\\Windows\\system32\\cmd.exe',
        DEBUG_COLORS: 'true',
        DriverData: 'C:\\Windows\\System32\\Drivers\\DriverData',
        ELECTRON_NO_ATTACH_CONSOLE: 'true',
        FORCE_COLOR: 'true',
        FPS_BROWSER_APP_PROFILE_STRING: 'Internet Explorer',
        FPS_BROWSER_USER_PROFILE_STRING: 'Default',
        HOMEDRIVE: 'C:',
        HOMEPATH: '\\Users\\qian0',
        LOCALAPPDATA: 'C:\\Users\\qian0\\AppData\\Local',
        LOGONSERVER: '\\\\DESKTOP-O11HVTS',
        MOCHA_COLORS: '1',
        MOZ_PLUGIN_PATH: 'D:\\tools\\edit\\foxit_Offline_FoxitInst\\Foxit Reader\\plugins\\',
        npm_config_color: 'always',
        NUMBER_OF_PROCESSORS: '4',
        OneDrive: 'C:\\Users\\qian0\\OneDrive',
        OneDriveConsumer: 'C:\\Users\\qian0\\OneDrive',
        OS: 'Windows_NT',
        Path: 'D:\\develop\\WebStorm-2019.2\\WebStorm 2019.2\\jbr\\\\bin;D:\\develop\\WebStorm-2019.2\\WebStorm 2019.2\\jbr\\\\bin\\server;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;D:\\develop\\nodejs\\;D:\\develop\\git\\Git\\cmd;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;D:\\develop\\Anaconda3-5.3.1-Windows-x86_64;D:\\develop\\Anaconda3-5.3.1-Windows-x86_64\\Library\\mingw-w64\\bin;D:\\develop\\Anaconda3-5.3.1-Windows-x86_64\\Library\\usr\\bin;D:\\develop\\Anaconda3-5.3.1-Windows-x86_64\\Library\\bin;D:\\develop\\Anaconda3-5.3.1-Windows-x86_64\\Scripts;D:\\develop\\python-3.7.4-amd64\\Scripts\\;D:\\develop\\python-3.7.4-amd64\\;C:\\Users\\qian0\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\qian0\\AppData\\Roaming\\npm;D:\\develop\\VSCode\\Microsoft VS Code\\bin;D:\\develop\\FiddlerSetup\\Fiddler;D:\\develop\\pycharm-community-2019.1.3\\bin;',
        PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
        PROCESSOR_ARCHITECTURE: 'AMD64',
        PROCESSOR_IDENTIFIER: 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel',
        PROCESSOR_LEVEL: '6',
        PROCESSOR_REVISION: '3a09',
        ProgramData: 'C:\\ProgramData',
        ProgramFiles: 'C:\\Program Files',
        'ProgramFiles(x86)': 'C:\\Program Files (x86)',
        ProgramW6432: 'C:\\Program Files',
        PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules',
        PUBLIC: 'C:\\Users\\Public',
        'PyCharm Community Edition': 'D:\\develop\\pycharm-community-2019.1.3\\bin;',
        SESSIONNAME: 'Console',
        SystemDrive: 'C:',
        SystemRoot: 'C:\\Windows',
        TEMP: 'C:\\Users\\qian0\\AppData\\Local\\Temp',
        TMP: 'C:\\Users\\qian0\\AppData\\Local\\Temp',
        USERDOMAIN: 'DESKTOP-O11HVTS',
        USERDOMAIN_ROAMINGPROFILE: 'DESKTOP-O11HVTS',
        USERNAME: 'qian0',
        USERPROFILE: 'C:\\Users\\qian0',
        windir: 'C:\\Windows'
    },
    pid: 8720,
    features: {
        debug: false,
        uv: true,
        ipv6: true,
        tls_alpn: true,
        tls_sni: true,
        tls_ocsp: true,
        tls: true
    },
    ppid: 7968,
    execPath: 'D:\\develop\\nodejs\\node.exe',
    debugPort: 9229,
    _debugProcess: [Function: _debugProcess],
    _debugEnd: [Function: _debugEnd],
    _startProfilerIdleNotifier: [Function: _startProfilerIdleNotifier],
    _stopProfilerIdleNotifier: [Function: _stopProfilerIdleNotifier],
    abort: [Function: abort],
    chdir: [Function: chdir],
    umask: [Function: umask],
    _getActiveRequests: [Function: _getActiveRequests],
    _getActiveHandles: [Function: _getActiveHandles],
    _kill: [Function: _kill],
    cwd: [Function: cwd],
    dlopen: [Function: dlopen],
    reallyExit: [Function: reallyExit],
    uptime: [Function: uptime],
    _rawDebug: [Function],
    moduleLoadList: ['Internal Binding module_wrap', 'Binding contextify', 'Internal Binding worker', 'NativeModule events', 'NativeModule internal/async_hooks', 'NativeModule internal/errors', 'Binding uv', 'Binding buffer', 'Binding async_wrap', 'Internal Binding async_wrap', 'Binding config', 'Binding icu', 'NativeModule util', 'NativeModule internal/util/inspect', 'Binding util', 'NativeModule internal/util', 'Binding constants', 'Internal Binding types', 'NativeModule internal/util/types', 'NativeModule internal/validators', 'NativeModule internal/encoding', 'Internal Binding icu', 'NativeModule buffer', 'NativeModule internal/buffer', 'NativeModule internal/process/per_thread', 'NativeModule internal/process/main_thread_only', 'NativeModule internal/process/stdio', 'NativeModule assert', 'NativeModule internal/assert', 'NativeModule fs', 'NativeModule path', 'NativeModule internal/constants', 'Binding fs', 'NativeModule internal/fs/streams', 'NativeModule internal/fs/utils', 'NativeModule stream', 'NativeModule internal/streams/pipeline', 'NativeModule internal/streams/end-of-stream', 'NativeModule internal/streams/legacy', 'NativeModule _stream_readable', 'NativeModule internal/streams/buffer_list', 'NativeModule internal/streams/destroy', 'NativeModule internal/streams/state', 'NativeModule _stream_writable', 'NativeModule _stream_duplex', 'NativeModule _stream_transform', 'NativeModule _stream_passthrough', 'NativeModule internal/url', 'NativeModule internal/querystring', 'Binding url', 'NativeModule internal/process/warning', 'NativeModule internal/process/next_tick', 'NativeModule internal/process/promises', 'Internal Binding util', 'NativeModule internal/fixed_queue', 'Binding performance', 'Binding trace_events', 'NativeModule internal/inspector_async_hook', 'Binding inspector', 'NativeModule internal/options', 'Internal Binding options', 'NativeModule timers', 'Binding timer_wrap', 'NativeModule internal/linkedlist', 'NativeModule internal/timers', 'NativeModule console', 'Binding tty_wrap', 'Internal Binding tty_wrap', 'NativeModule net', 'NativeModule internal/net', 'Binding stream_wrap', 'Binding tcp_wrap', 'Binding pipe_wrap', 'NativeModule internal/stream_base_commons', 'Internal Binding stream_wrap', 'Internal Binding uv', 'NativeModule internal/modules/cjs/loader', 'NativeModule vm', 'NativeModule internal/modules/cjs/helpers', 'NativeModule url', 'NativeModule internal/safe_globals', 'Internal Binding contextify'],
    binding: [Function: binding],
    _linkedBinding: [Function: _linkedBinding],
    _events: [Object: null prototype] {
        newListener: [Function],
        removeListener: [Function],
        warning: [Function]
    },
    _eventsCount: 3,
    _maxListeners: undefined,
    _fatalException: [Function],
    domain: null,
    _exiting: false,
    assert: [Function: deprecated],
    config: {
        target_defaults: {
            cflags: [],
            default_configuration: 'Release',
            defines: [],
            include_dirs: [],
            libraries: []
        },
        variables: {
            asan: 0,
            build_v8_with_gn: false,
            coverage: false,
            debug_nghttp2: false,
            enable_lto: false,
            enable_pgo_generate: false,
            enable_pgo_use: false,
            force_dynamic_crt: 0,
            host_arch: 'x64',
            icu_data_in: '..\\..\\deps/icu-small\\source/data/in\\icudt64l.dat',
            icu_endianness: 'l',
            icu_gyp_path: 'tools/icu/icu-generic.gyp',
            icu_locales: 'en,root',
            icu_path: 'deps/icu-small',
            icu_small: true,
            icu_ver_major: '64',
            nasm_version: '2.14',
            node_byteorder: 'little',
            node_debug_lib: false,
            node_enable_d8: false,
            node_enable_v8_vtunejit: false,
            node_install_npm: true,
            node_module_version: 64,
            node_no_browser_globals: false,
            node_prefix: '/usr/local',
            node_release_urlbase: 'https://nodejs.org/download/release/',
            node_shared: false,
            node_shared_cares: false,
            node_shared_http_parser: false,
            node_shared_libuv: false,
            node_shared_nghttp2: false,
            node_shared_openssl: false,
            node_shared_zlib: false,
            node_tag: '',
            node_target_type: 'executable',
            node_use_bundled_v8: true,
            node_use_dtrace: false,
            node_use_etw: true,
            node_use_large_pages: false,
            node_use_openssl: true,
            node_use_pch: false,
            node_use_perfctr: true,
            node_use_v8_platform: true,
            node_with_ltcg: true,
            node_without_node_options: false,
            openssl_fips: '',
            openssl_no_asm: 0,
            shlib_suffix: 'so.64',
            target_arch: 'x64',
            v8_enable_gdbjit: 0,
            v8_enable_i18n_support: 1,
            v8_enable_inspector: 1,
            v8_no_strict_aliasing: 1,
            v8_optimized_debug: 0,
            v8_promise_internal_field_count: 1,
            v8_random_seed: 0,
            v8_trace_maps: 0,
            v8_typed_array_max_size_in_heap: 0,
            v8_use_snapshot: true,
            want_separate_host_toolset: 0
        }
    },
    setUncaughtExceptionCaptureCallback: [Function],
    hasUncaughtExceptionCaptureCallback: [Function],
    emitWarning: [Function],
    nextTick: [Function: nextTick],
    _tickCallback: [Function: _tickCallback],
    stdout: [Getter],
    stderr: [Getter],
    stdin: [Getter],
    openStdin: [Function],
    hrtime: { [Function: hrtime] bigint: [Function]
    },
    cpuUsage: [Function: cpuUsage],
    memoryUsage: [Function: memoryUsage],
    exit: [Function],
    kill: [Function],
    argv0: 'D:\\develop\\nodejs\\node.exe',
    allowedNodeEnvironmentFlags: [Getter / Setter],
    mainModule: Module {
        id: '.',
        exports: {},
        parent: null,
        filename: 'E:\\linfeimy\\02personal\\Node.js-Demo\\Node.js v10.6.2\\events\\index.js',
        loaded: false,
        children: [],
        paths: ['E:\\linfeimy\\02personal\\Node.js-Demo\\Node.js v10.6.2\\events\\node_modules', 'E:\\linfeimy\\02personal\\Node.js-Demo\\Node.js v10.6.2\\node_modules', 'E:\\linfeimy\\02personal\\Node.js-Demo\\node_modules', 'E:\\linfeimy\\02personal\\node_modules', 'E:\\linfeimy\\node_modules', 'E:\\node_modules']
    }
}
linfeimy commented 5 years ago
const EventEmitter = require('events');

console.log(EventEmitter);
{ [Function: EventEmitter] once: [Function: once],
    EventEmitter: [Circular],
    usingDomains: false,
    defaultMaxListeners: [Getter / Setter],
    init: [Function],
    listenerCount: [Function]
}

const EventEmitter = require('events');

// console.log(EventEmitter);

class MyEmitter extends EventEmitter {};

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
    console.log('触发事件');
});

setTimeout(() => {
    myEmitter.emit('event');
}, 3000);
linfeimy commented 5 years ago

将参数和 this 传给监听器 eventEmitter.emit() 方法可以传任意数量的参数到监听器函数。 当监听器函数被调用时, this 关键词会被指向监听器所绑定的 EventEmitter 实例。

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {};

const myEmitter = new MyEmitter();

myEmitter.on('event', function (a, b) {
    console.log(a + '\n', b + '\n', this );
    console.log(this === myEmitter);
});
myEmitter.emit('event');

// undefined
// undefined
/*
    MyEmitter {
        _events: [Object: null prototype] {
            event: [Function]
        },
        _eventsCount: 1,
            _maxListeners: undefined
    }
*/

// true

改为myEmitter.emit('event', 'a', 'b');

// a
// b
/*
    MyEmitter {
        _events: [Object: null prototype] {
            event: [Function]
        },
        _eventsCount: 1,
            _maxListeners: undefined
    }
*/

// true

也可以使用 ES6 的箭头函数作为监听器。但 this 关键词不会指向 EventEmitter 实例:

myEmitter.on('event', (a, b) => {
    console.log(a + '\n', b + '\n', this );
    console.log(this === myEmitter);
});

myEmitter.emit('event', 'a', 'b');

// a
// b
// {}
// false
linfeimy commented 5 years ago

异步 VS 同步 EventEmitter 会按照监听器注册的顺序同步地调用所有监听器。 所以必须确保事件的排序正确,且避免竞态条件。 可以使用 setImmediate()process.nextTick()切换到异步模式:

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

myEmitter.on('event', (a, b) => {
    console.log(1);
    setImmediate(() => {
        console.log('异步进行');
    });
    console.log(2);
});
myEmitter.emit('event', 'a', 'b');

// 1
// 2
// 异步进行
linfeimy commented 5 years ago

仅处理事件一次 当使用 eventEmitter.on()注册监听器时,监听器会在每次触发命名事件时被调用。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

let m = 0;
myEmitter.on('event', () => {
    console.log(++m);
});

myEmitter.emit('event'); // 1
myEmitter.emit('event'); // 2

使用eventEmitter.once() 可以注册最多可调用一次的监听器。 当事件被触发时,监听器会被注销,然后再调用。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

let m = 0;
myEmitter.once('event', () => {
    console.log(++m);
});

myEmitter.emit('event'); // 1
myEmitter.emit('event'); 
linfeimy commented 5 years ago

错误事件 当 EventEmitter 实例出错时,应该触发 'error' 事件。 这些在 Node.js 中被视为特殊情况。

如果没有为 'error' 事件注册监听器,则当 'error' 事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

myEmitter.emit('error', new Error('错误消息'));

//  throw er; // Unhandled 'error' event
//  Error: 错误消息

为了防止崩溃 Node.js 进程,可以使用 domain 模块。 (但请注意,不推荐使用 domain 模块。)

作为最佳实践,应该始终为 'error' 事件注册监听器。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

myEmitter.on('error', (err) => {
    console.error('错误消息');
})

myEmitter.emit('error', new Error('错误消息'));

// 错误消息
linfeimy commented 5 years ago

events.once(emitter, name) 创建一个 Promise,当 EventEmitter 触发给定的事件时则会被解决,当 EventEmitter 触发 'error' 时则会被拒绝。 解决 Promise 时将会带上触发到给定事件的所有参数的数组。

const { once, EventEmitter } = require('events');
async function run() {
    const ee = new EventEmitter();
    process.nextTick(() => {
        ee.emit('myEvent', 42);
    });

    const [value] = await once(ee, 'myEvent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
        ee.emit('error', err);
    });

    try {
        await once(ee, 'myEvent');
    } catch (e) {
        console.log('出错', err);
    }
}

run();