Node.js | 青训营笔记


theme: condensed-night-purple

highlight: a11y-dark

这是我参与「第四届青训营 」笔记创作活动的的第15天

https://www.runoob.com/nodejs/nodejs-tutorial.html

Node.js 应用是由哪几部分组成的:

引入 required 模块:我们可以使用 require 指令来载入 Node.js 模块。

创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。

接收请求与响应请求 服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。

```js // 使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http: var http = require("http");

// 创建服务器 // 使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。 // 函数通过 request, response 参数来接收和响应数据

http.createServer(function (request, response) {

// 发送 HTTP 头部 
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});

// 发送响应数据 "Hello World"
response.end('Hello World\n');

}).listen(8888);

// 终端打印如下信息 console.log('Server running at http://127.0.0.1:8888/'); ```

分析Node.js 的 HTTP 服务器:

第一行请求(require)Node.js 自带的 http 模块,并且把它赋值给 http 变量。

接下来我们调用 http 模块提供的函数: createServer 。这个函数会返回 一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。

Node.js 事件循环

  • Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件

```js // 引入 events 模块 var events = require('events'); // 创建 eventEmitter 对象 var eventEmitter = new events.EventEmitter();

// 绑定事件及事件的处理程序 eventEmitter.on('eventName', eventHandler);

// 触发事件 eventEmitter.emit('eventName');

// 实例
    // 引入 events 模块
    var events = require('events');
    // 创建 eventEmitter 对象
    var eventEmitter = new events.EventEmitter();

    // 创建事件处理程序
    var connectHandler = function connected() {
        console.log('连接成功。');

        // 触发 data_received 事件 
        eventEmitter.emit('data_received');
    }

    // 绑定 connection 事件处理程序
    eventEmitter.on('connection', connectHandler);

    // 使用匿名函数绑定 data_received 事件
    eventEmitter.on('data_received', function () {
        console.log('数据接收成功。');
    });

    // 触发 connection 事件 
    eventEmitter.emit('connection');

    console.log("程序执行完毕。");

```

Node.js EventEmitter

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
```js // 引入 events 模块 var events = require('events'); // 创建 eventEmitter 对象 var eventEmitter = new events.EventEmitter();

//event.js 文件
var EventEmitter = require('events').EventEmitter; 
var event = new EventEmitter(); 
event.on('some_event', function() { 
    console.log('some_event 事件触发'); 
}); 
setTimeout(function() { 
    event.emit('some_event'); 
}, 1000);

```

对于每个事件,EventEmitter 支持 若干个事件监听器。

当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

EventEmitter 的属性

方法

  1. addListener(event, listener) 为指定事件添加一个监听器到监听器数组的尾部

  2. on(event, listener) 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数 js server.on('connection', function (stream) { console.log('someone connected!'); });

  3. once(event, listener) 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器 js server.once('connection', function (stream) { console.log('Ah, we have our first user!'); });

  4. removeListener(event, listener)

    移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。

    它接受两个参数,第一个是事件名称,第二个是回调函数名称。 js var callback = function(stream) { console.log('someone connected!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback);

  5. removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器

  6. setMaxListeners(n) 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于改变监听器的默认限制的数量。

  7. listeners(event) 返回指定事件的监听器数组

  8. emit(event, [arg1], [arg2], [...]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false

  9. events.emitter.listenerCount(eventName) / eventEmitter.listeners('connection').length 返回指定事件的监听器数量

```js // 实例 var events = require('events'); var eventEmitter = new events.EventEmitter();

// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
}

// 监听器 #2
var listener2 = function listener2() {
console.log('监听器 listener2 执行。');
}

// 绑定 connection 事件,处理函数为 listener1 
eventEmitter.addListener('connection', listener1);

// 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection', listener2);

var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

// 处理 connection 事件 
eventEmitter.emit('connection');

// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。");

// 触发连接事件
eventEmitter.emit('connection');

eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

console.log("程序执行完毕。");


// 以上代码,执行结果如下所示:

// $ node main.js
// 2 个监听器监听连接事件。
// 监听器 listener1 执行。
// 监听器 listener2 执行。
// listener1 不再受监听。
// 监听器 listener2 执行。
// 1 个监听器监听连接事件。
// 程序执行完毕。

``` https://www.runoob.com/nodejs/nodejs-event.html

# Node.js Buffer(缓冲区)

https://www.runoob.com/nodejs/nodejs-buffer.html

Node.js Stream(流)

Stream 是一个抽象接口

Node.js,Stream 有四种流类型:

Readable - 可读操作。
Writable - 可写操作。
Duplex - 可读可写操作.
Transform - 操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

data - 当有数据 可读 时触发。
end -  没有 更多的数据可读时触发。
error - 在接收和写入过程中 发生错误 时触发
finish - 所有数据 已被写入 到底层系统时触发。

教程 : https://www.runoob.com/nodejs/nodejs-stream.html

```js // 从流中读取数据 var fs = require("fs"); var data = '';

// 创建可读流
    var readerStream = fs.createReadStream('input.txt');

    // 设置编码为 utf8。
    readerStream.setEncoding('UTF8');

    // 处理流事件 --> data, end, and error
    readerStream.on('data', function(chunk) {
    data += chunk;
    });

    readerStream.on('end',function(){
    console.log(data);
    });

// 写入流 var fs = require("fs"); var data = '菜鸟教程官网地址:www.runoob.com';

// 创建一个可以写入的流,写入到文件 output.txt 中
    var writerStream = fs.createWriteStream('output.txt');

    // 使用 utf8 编码写入数据
    writerStream.write(data,'UTF8');

    // 标记文件末尾
    writerStream.end();

    // 处理流事件 --> finish、error
    writerStream.on('finish', function() {
        console.log("写入完成。");
    });

writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");

```

管道流

管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中

用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程

```js // 通过读取一个文件内容并将内容写入到另外一个文件中 var fs = require("fs");

// 创建一个可读流
    var readerStream = fs.createReadStream('input.txt');

    // 创建一个可写流
    var writerStream = fs.createWriteStream('output.txt');

    // 管道读写操作
    // 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
    readerStream.pipe(writerStream);

    console.log("程序执行完毕");

```

链式流

链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

```js // 用管道和链式来压缩和解压文件

const fs = require("fs");
const zlib = require('zlib');

    // 压缩 input.txt 文件为 input.txt.gz
    fs.createReadStream('input.txt')
    .pipe(zlib.createGzip())
    .pipe(fs.createWriteStream('input.txt.gz'));

    console.log("文件压缩完成。");


    // 解压 input.txt.gz 文件为 input.txt
    fs.createReadStream('input.txt.gz')
    .pipe(zlib.createGunzip())
    .pipe(fs.createWriteStream('input.txt'));

console.log("文件解压完成。");

```

Node.js模块系统

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展

Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象

引入模块

js var hello = require('./hello'); // 代码 require('./hello') 引入了当前目录下的 hello.js 文件(./ 为当前目录,node.js 默认后缀为 js) 详情见模块化开发

服务端的模块放在哪里

详见 : https://www.runoob.com/nodejs/nodejs-module-system.html

  • Node.js 的 require 方法中的文件查找策略如下

    1. 从文件模块缓存中加载

      尽管原生模块与文件模块的优先级不同,但是都会优先从文件模块的缓存中加载已经存在的模块。

    2. 从原生模块加载

      原生模块的优先级仅次于文件模块缓存的优先级。require 方法在解析文件名之后,优先检查模块是否在原生模块列表中。以http模块为例,尽管在目录下存在一个 http/http.js/http.node/http.json 文件,require("http") 都不会从这些文件中加载,而是从原生模块中加载。

      原生模块也有一个缓存区,同样也是优先从缓存区加载。如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。

    3. 从文件加载

      当文件模块缓存中不存在,而且不是原生模块的时候,Node.js 会解析 require 方法传入的参数,并从文件系统中加载实际的文件,加载过程中的包装和编译细节在前一节中已经介绍过,这里我们将详细描述查找文件模块的过程,其中,也有一些细节值得知晓。

      require方法接受以下几种参数的传递:

      http、fs、path等,原生模块。
      ./mod或../mod,相对路径的文件模块。
      /pathtomodule/mod,绝对路径的文件模块。
      mod,非原生模块的文件模块。

exports 和 module.exports 的使用 如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports

Node.js 函数

一个函数可以作为另一个函数的参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数(匿名函数)

Node.js 路由

我们要为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码

详见 : https://www.runoob.com/nodejs/nodejs-router.html

```js // router.js 文件代码: function route(pathname) { console.log("About to route a request for " + pathname); }

exports.route = route;

// server.js 文件代码: var http = require("http"); var url = require("url");

function start(route) {
function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");

    route(pathname);

    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
}

http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}

exports.start = start;

// index.js 文件代码: var server = require("./server"); var router = require("./router");

server.start(router.route);

// out : Server has started. ```

Node.js 全局对象

Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性

它及其所有属性都可以在程序的任何地方访问,即全局变量

全局对象与全局变量

global 最根本的作用是作为全局变量的宿主

  • 满足以下条 件的变量是全局变量: 在最外层定义的变量; 全局对象的属性; 隐式定义的变量(未定义直接赋值的变量)

当你定义一个全局变量时,这个变量同时也会成为全局对象的属性

注意: 最好不要使用 var 定义变量以避免引入全局变量,因为全局变量会污染命名空间,提高代码的耦合风险

__filename

表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径

__dirname

__dirname 表示当前执行脚本所在的目录

setTimeout(cb, ms)

setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行 一次 指定函数。

返回一个代表定时器的句柄值。

clearTimeout(t)

clearTimeout( t ) 全局函数用于 停止 一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。

```js function printHello(){ console.log( "Hello, World!"); } // 两秒后执行以上函数 var t = setTimeout(printHello, 2000);

// 清除定时器
clearTimeout(t);

```

setInterval(cb, ms)

setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。

返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。

setInterval() 方法会 不停地 调用函数,直到 clearInterval() 被调用 或窗口被 关闭

js function printHello(){ console.log( "Hello, World!"); } // 两秒后执行以上函数 setInterval(printHello, 2000); // 以上程序每隔两秒就会输出一次"Hello, World!",且会永久执行下去,直到你按下 ctrl + c 按钮。

console

console 用于提供控制台标准输出, 用于向标准输出流(stdout)或标准错误流(stderr)输出字符

  • console 方法
  • console.log([data][, ...]) : 向标准输出流打印字符并以 换行符结束。 该方法接收若干 个参数,如果只有一个参数,则输出这个参数的字符串形式。如果有多个参数,则 以类似于C 语言 printf() 命令的格式输出。如果没有 参数,只打印一个换行 js console.log('Hello world'); console.log('byvoid%diovyb'); console.log('byvoid%diovyb', 1991); // Hello world // byvoid%diovyb // byvoid1991iovyb
  1. console.time(label) : 输出时间,表示计时开始。
  2. console.timeEnd(label) : 结束时间,表示计时结束。
  3. console.error([data][, ...]) : 输出错误消息的。控制台在出现错误时会显示是红色的叉子。
  4. console.warn([data][, ...]) : 输出警告消息。控制台出现有黄色的惊叹号。

详见 :https://www.runoob.com/nodejs/nodejs-global-object.html

process

process 是一个全局变量,即 global 对象的属性。

它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。下面将会介绍 process 对象的一些最常用的成员方法。

详见 :https://www.runoob.com/nodejs/nodejs-global-object.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值