Node.js之events模块

一、前言

我们经常说JS 是单线程执行的,指的是一个进程里只有一个主线程,那到底什么是线程?什么是进程?

1. 进程与线程的概念理解

😳 官方的说法是

进程是 CPU资源分配的最小单位;线程是 CPU调度的最小单位

😀 通俗的理解是

上面两句话并不好理解,我们先来看张图


我们可以将进程比作图中的工厂,有单独的专属自己的工厂资源。线程好比图中的工人,多个工人在一个工厂中协作工作,工厂与工人是 1:n的关系。也就是说一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;工厂的空间是工人们共享的,这象征一个进程的内存空间是共享的,每个线程都可用这些共享内存。多个工厂之间独立存在。

2.多进程与多线程

☘️ 多进程

在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态。多进程带来的好处是明显的,比如你可以听歌的同时,打开编辑器敲代码,编辑器和听歌软件的进程之间丝毫不会相互干扰。

☘️ 多线程

程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

以Chrome浏览器中为例,当你打开一个 Tab 页时,其实就是创建了一个进程,一个进程中可以有多个线程(下文会详细介绍),比如渲染线程、JS 引擎线程、HTTP 请求线程等等。当你发起一个请求时,其实就是创建了一个线程,当请求结束后,该线程可能就会被销毁。

二、事件机制events

events模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http、fs等。

模块本身非常简单,API虽然也不少,但常用的就那么几个,这里举几个简单例子。

下面一共是6个例子,都非常简单,可以直接拷贝出来运行。例子5比较有意思,虽然也并不复杂,但确实是容易记错的点,感兴趣的同学可以看下。

例子1:单个事件监听器

var EventEmitter = require('events');

class Man extends EventEmitter { }

var man = new Man();

man.on('wakeup', function () {
    console.log('man has woken up');
});

man.emit('wakeup');
// 输出如下:
// man has woken up

例子2:同个事件,多个事件监听器

可以看到,事件触发时,事件监听器按照注册的顺序执行。

var EventEmitter = require('events');

class Man extends EventEmitter {}

var man = new Man();

man.on('wakeup', function(){
    console.log('man has woken up');
});

man.on('wakeup', function(){
    console.log('man has woken up again');
});

man.emit('wakeup');

// 输出如下:
// man has woken up
// man has woken up again

例子3:只运行一次的事件监听器

var EventEmitter = require('events');

class Man extends EventEmitter {}

var man = new Man();

man.on('wakeup', function(){
    console.log('man has woken up');
});

man.once('wakeup', function(){
    console.log('man has woken up again');
});

man.emit('wakeup');
man.emit('wakeup');

// 输出如下:
// man has woken up
// man has woken up again
// man has woken up

例子4:注册事件监听器前,事件先触发

可以看到,注册事件监听器前,事件先触发,则该事件会直接被忽略。

var EventEmitter = require('events');

class Man extends EventEmitter {}

var man = new Man();

man.emit('wakeup', 1);

man.on('wakeup', function(index){
    console.log('man has woken up ->' + index);
});

man.emit('wakeup', 2);
// 输出如下:
// man has woken up ->2

例子5:异步执行,还是顺序执行

例子很简单,但非常重要。究竟是代码1先执行,还是代码2先执行,这点差异,无论对于我们理解别人的代码,还是自己编写node程序,都非常关键。

实践证明,代码1先执行了。(node v6.1.0)

var EventEmitter = require('events');

class Man extends EventEmitter {}

var man = new Man();

man.on('wakeup', function(){
    console.log('man has woken up'); // 代码1
});

man.emit('wakeup');

console.log('woman has woken up');  // 代码2

// 输出如下:
// man has woken up
// woman has woken up

例子6:移除事件监听器

var EventEmitter = require('events');

function wakeup(){
    console.log('man has woken up');
}

class Man extends EventEmitter {}

var man = new Man();

man.on('wakeup', wakeup);
man.emit('wakeup');

man.removeListener('wakeup', wakeup);
man.emit('wakeup');

// 输出如下:
// man has woken up

posted on 2024-07-18 22:10  梁飞宇  阅读(9)  评论(0)    收藏  举报