Node.js了解

目录
  1. Hello World
  2. 创建第一个Node.js应用
  3. REPL (调试Javascript)
  4. 回调函数
  5. 事件循环
  6. 函数
  7. 模块系统
  8. 路由

少壮不努力,老大徒伤悲。

本文为本人略读官网文档后的大略笔记,实在不适合他人阅读。

前言

Node.js : 运行在服务端的JavaScript

是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎。

安装

安装node
brew install node

查看当前node版本
node -v

1. Hello World

创建test.js (内容如下)

console.log("Hello World"); 

终端执行 node test.js

输出Hello World
效果图
交互模式(终端输入node)效果图

2. 创建第一个Node.js应用

Node.js应用的组成部分

1. 引入required模块
  使用require指令来载入Node.js模块。

2. 创建服务器
  服务器监听客户端请求。
  Apache、Nginx等HTTP 服务器。

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

步骤1: 引入required模块

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

步骤2: 创建服务器

创建 server.js文件

var http = require('http');

// 创建服务器
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(8088);

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

终端运行 node server.js

如果运行出错,可能是端口号冲突,换一个端口即可。
运行效果

3. REPL (调试Javascript)

REPL(Read Eval Print Loop:交互式解释器)
一个电脑的环境,类似 Window 系统的终端或 Unix/Linux shell,我们可以在终端中输入命令,并接收系统的响应。

Node自带了交互式解释器,可以执行以下任务:
    1. 读取 
      读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
    2. 执行 
      执行输入的数据结构
    3. 打印
      输出结果
    4. 循环
      循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。
退出当前终端
    ctrl + c 。

按下两次 - 退出 Node REPL
    ctrl + c 。

退出 Node REPL
    ctrl + d - 

查看输入的历史命令
    向上/向下键 

补全当前命令
    tab 键 

列出可使用命令
    .help  

退出多行表达式
    .break 

退出多行表达式
    .clear 

保存当前的 Node REPL 会话到指定文件
    .save filename  

载入当前 Node REPL 会话的文件内容
    .load filename 

首先,在终端输入node

可使用
  1. 表达式运算
  2. 变量
  3. 多行语句
  4. _获取上一个表达式的值
运行效果

4. 回调函数

Node 所有 API 都支持回调函数

回调函数一般作为函数的最后一个参数出现
  function foo1(name, age, callback) { }
  function foo2(value, callback1, callback2) { }

例1 (阻塞)

创建content.txt文件

Hello World!
Hello cx,,,

创建main.js文件

var fs = require("fs");

var data = fs.readFileSync('content.txt');
console.log(data.toString());
console.log("程序执行结束!");

终端执行 node main.js

Hello World!
Hello cx,,,
程序执行结束!

例2 (非阻塞)

创建content.txt文件

Hello World!
Hello cx,,,

创建main.js文件

var fs = require("fs");

fs.readFile('content.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});
console.log("程序执行结束!");

终端执行 node main.js

程序执行结束!
Hello World!
Hello cx,,,

5. 事件循环

NOde.js是单进程单线程应用程序,但V8引擎提供了异步执行回调接口,可处理大量的并发,所以性能非常高。
几乎所有API都支持回调函数。
几乎所有事件机制都是通过观察者模式实现的。
第一步:导入事件模块,创建eventEmitter 对象
第二步:绑定事件
    回调函数作为最后一个参数。
    err对象作为回调函数第一个参数。
    当添加新的监听器时,newListener 事件会触发。
    当监听器被移除时,removeListener 事件被触发。
第三步:触发事件
    类似于观察者模式,所有注册在某一事件上的处理函数都相当于观察者。当事件触发时依次调用处理函数。

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

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

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

例1

创建test.js文件(内容如下)
执行node test.js 输出:
  连接成功。
  数据接收成功。
  程序执行完毕。
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象(在实例化时发生错误,会触发 error 事件)
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("程序执行完毕。");

例2(err:回调函数的第一个参数)

============== input.txt ==============
Hello World!
Hello cx,,,

============== test.js ==============
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
   if (err){
      console.log(err.stack);
      return;
   }
   console.log(data.toString());
});
console.log("程序执行完毕");

============== node test.js ==============
程序执行完毕
Hello World!
Hello cx,,,
==============删除input.txt node test.js ==============
程序执行完毕
Error: ENOENT: no such file or directory, open 'input.txt'

例3

输出:
  listener1 arg1 参数 arg2 参数
  listener2 arg1 参数 arg2 参数
//event.js 文件
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 
  1. EventEmitter

多数情况下不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

通过require("events");导入events模块。
events模块只提供了一个对象,就是events.EventEmitter。
EventEmitter的核心就是对事件触发与事件监听器功能进行封装。
EventEmitter的每个事件由一个事件名和若干个参数组成。事件名是一个字符串。

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
Node.js 里面的许多对象都会分发事件:
  一个 net.Server 对象会在每次有新连接时触发一个事件
  一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 

所有这些产生事件的对象都是 events.EventEmitter 的实例。
方法名 描述
addListener(event, listener) 为指定事件添加一个监听器(添加到监听器数组的尾部)。
on(event, listener) 为指定事件注册一个监听器(接受一个字符串 event 和一个回调函数)。 server.on('connection', function (stream) { console.log('someone connected!'); });
once(event, listener) 为指定事件注册一个单次监听器(即监听器最多只会触发一次,触发后立刻解除该监听器)。 server.once('connection', function (stream) { console.log('Ah, we have our first user!'); });
removeListener(event, listener) 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。它接受两个参数,第一个是事件名称,第二个是回调函数名称。 var callback = function(stream) { console.log('someone connected!'); }; server.on('connection', callback); server.removeListener('connection', callback);
removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
setMaxListeners(n) 默认情况下, EventEmitters添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
listeners(event) 返回指定事件的监听器数组。
emit(event, [arg1], [arg2], [...]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
listenerCount(emitter, event) 类方法。返回指定事件的监听器数量。 events.EventEmitter.listenerCount(emitter, eventName) //已废弃,不推荐 events.emitter.listenerCount(eventName) //推荐
事件 描述
newListener event - 字符串,事件名称。listener - 处理事件函数。该事件在添加新监听器时被触发。
removeListener event - 字符串,事件名称。listener - 处理事件函数。从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。
error 事件 在遇到 异常的时候通常会触发 error 事件。如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。 var events = require('events'); var emitter = new events.EventEmitter(); emitter.emit('error');

例1

输出

2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕。 
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("程序执行完毕。");
 大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发生应该是一个对象的方法。
其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。

6. 函数

函数作参

在JavaScript中,一个函数可以作为另一个函数的参数。

function say(word) {
  console.log(word);
}
function execute(someFunction, value) {
  someFunction(value);
}
execute(say, "Hello");

匿名函数

function execute(someFunction, value) {
  someFunction(value);
}

execute(function(word){ console.log(word) }, "Hello");

http.createServer方法就是传入了一个匿名函数

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);
==================等价
function onRequest(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}
http.createServer(onRequest).listen(8888);

7. 模块系统

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

Node.js提供了exports、require两个对象,分别用于导出、导入。

exports 
  暴露属性和方法
module.exports
  暴露对象
require 方法中的文件查找策略

Node.js存在4类模块(原生模块和3种文件模块)

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

在路径 Y 下执行 require(X) 语句执行顺序

1. 如果 X 是内置模块
   a. 返回内置模块
   b. 停止执行
2. 如果 X 以 '/' 开头
   a. 设置 Y 为文件根路径
3. 如果 X 以 './' 或 '/' or '../' 开头
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. 抛出异常 "not found"

LOAD_AS_FILE(X)
1. 如果 X 是一个文件, 将 X 作为 JavaScript 文本载入并停止执行。
2. 如果 X.js 是一个文件, 将 X.js 作为 JavaScript 文本载入并停止执行。
3. 如果 X.json 是一个文件, 解析 X.json 为 JavaScript 对象并停止执行。
4. 如果 X.node 是一个文件, 将 X.node 作为二进制插件载入并停止执行。

LOAD_INDEX(X)
1. 如果 X/index.js 是一个文件,  将 X/index.js 作为 JavaScript 文本载入并停止执行。
2. 如果 X/index.json 是一个文件, 解析 X/index.json 为 JavaScript 对象并停止执行。
3. 如果 X/index.node 是一个文件,  将 X/index.node 作为二进制插件载入并停止执行。

LOAD_AS_DIRECTORY(X)
1. 如果 X/package.json 是一个文件,
   a. 解析 X/package.json, 并查找 "main" 字段。
   b. let M = X + (json main 字段)
   c. LOAD_AS_FILE(M)
   d. LOAD_INDEX(M)
2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIRS + DIR
   d. let I = I - 1
5. return DIRS

例1(创建模块)

================ hello.js ================
// 导出world
exports.world = function() {
  console.log('Hello World');
}
================ test.js ================
// ./ 为当前目录,node.js 默认后缀为 js
var hello = require('./hello');
hello.world();

例2(当只导出一个对象时)

module.exports = function() {
  // ...
}


如:http模块
var http = require("http");
http.createServer(...);
================  hello.js ================
//hello.js 
function Hello() { 
    var name; 
    this.setName = function(thyName) { 
        name = thyName; 
    }; 
    this.sayHello = function() { 
        console.log('Hello ' + name); 
    }; 
}; 
module.exports = Hello;
================  main.js ================
//main.js 
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello(); 

8. 路由

屏幕快照 2020-04-03 11.09.49.png

. 工具 模块

  1. OS 模块(系统操作函数)
引入

var os = require("os")
函数 说明
os.tmpdir() 返回操作系统的默认临时文件夹。
os.endianness() 返回 CPU 的字节序,可能的是 "BE" 或 "LE"。
os.hostname() 返回操作系统的主机名。
os.type() 返回操作系统名
os.platform() 返回编译时的操作系统名
os.arch() 返回操作系统 CPU 架构,可能的值有 "x64"、"arm" 和 "ia32"。
os.release() 返回操作系统的发行版本。
os.uptime() 返回操作系统运行的时间,以秒为单位。
os.loadavg() 返回一个包含 1、5、15 分钟平均负载的数组。
os.totalmem() 返回系统内存总量,单位为字节。
os.freemem() 返回操作系统空闲内存量,单位是字节。
os.cpus() 返回一个对象数组,包含所安装的每个 CPU/内核的信息:型号、速度(单位 MHz)、时间(一个包含 user、nice、sys、idle 和 irq 所使用 CPU/内核毫秒数的对象)。
os.networkInterfaces() 获得网络接口列表。
属性 说明
os.EOL 定义了操作系统的行尾符的常量

例1 (test.js)

var os = require("os");

// CPU 的字节序
console.log('endianness : ' + os.endianness());

// 操作系统名
console.log('type : ' + os.type());

// 操作系统名
console.log('platform : ' + os.platform());

// 系统内存总量
console.log('total memory : ' + os.totalmem() + " bytes.");

// 操作系统空闲内存量
console.log('free memory : ' + os.freemem() + " bytes.");
node test.js输出

endianness : LE
type : Darwin
platform : darwin
total memory : 17179869184 bytes.
free memory : 562544640 bytes.
  1. Path 模块 (处理文件路径的小工具)
引入

var path = require("path")
函数 说明
path.normalize(p) 规范化路径,注意'..' 和 '.'。
path.join([path1][, path2][, ...]) 用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是""。
path.resolve([from ...], to) 将 to 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve('/foo', '/bar', 'baz') 会返回 /bar/baz。
path.isAbsolute(path) 判断参数 path 是否是绝对路径。
path.relative(from, to) 用于将绝对路径转为相对路径,返回从 from 到 to 的相对路径(基于当前工作目录)。
path.dirname(p) 返回路径中代表文件夹的部分,同 Unix 的dirname 命令类似。
path.basename(p[, ext]) 返回路径中的最后一部分。同 Unix 命令 bashname 类似。
path.extname(p) 返回路径中文件的后缀名,即路径中最后一个'.'之后的部分。如果一个路径中并不包含'.'或该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
path.parse(pathString) 返回路径字符串的对象。
path.format(pathObject) 从对象中返回路径字符串,和 path.parse 相反。
属性 说明
path.sep 平台的文件路径分隔符,'\' 或 '/'。
path.delimiter 平台的分隔符, ; or ':'.
path.posix 提供上述 path 的方法,不过总是以 posix 兼容的方式交互。
path.win32 提供上述 path 的方法,不过总是以 win32 兼容的方式交互。
path.resolve([from ...], to)   例:

// 返回: '/foo/bar/baz'    
path.resolve('/foo/bar', './baz');  
// 返回: '/tmp/file'  
path.resolve('/foo/bar', '/tmp/file/');  
// 如果当前工作目录为 /home/myself/node,则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');  
path.relative(from, to)

在 Linux 上:
path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb');
// 返回: '../../impl/bbb'

在 Windows 上:
path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb');
// 返回: '..\\..\\impl\\bbb'

例1(test.js)

var path = require("path");

// 格式化路径
console.log('normalization : ' + path.normalize('/test/test1//2slashes/1slash/tab/..'));

// 连接路径
console.log('joint path : ' + path.join('/test', 'test1', '2slashes/1slash', 'tab', '..'));

// 转换为绝对路径
console.log('resolve : ' + path.resolve('main.js'));

// 路径中文件的后缀名
console.log('ext name : ' + path.extname('main.js'));
ode test.js输出

normalization : /test/test1/2slashes/1slash
joint path : /test/test1/2slashes/1slash
resolve : /Users/cx/Desktop/nodejs/main.js
ext name : .js
  1. Net 模块(用于底层的网络通信的小工具,包含了创建服务器/客户端的方法)
引入

var net = require("net")
函数 说明
net.createServer([options][, connectionListener]) 创建一个 TCP 服务器。参数 connectionListener 自动给 'connection' 事件创建监听器。
net.connect(options[, connectionListener]) 返回一个新的 'net.Socket',并连接到指定的地址和端口。当 socket 建立的时候,将会触发 'connect' 事件。
net.createConnection(options[, connectionListener]) 创建一个到端口 port 和 主机 host的 TCP 连接。 host 默认为 'localhost'。
net.connect(port[, host][, connectListener]) 创建一个端口为 port 和主机为 host的 TCP 连接 。host 默认为 'localhost'。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
net.createConnection(port[, host][, connectListener]) 创建一个端口为 port 和主机为 host的 TCP 连接 。host 默认为 'localhost'。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
net.connect(path[, connectListener]) 创建连接到 path 的 unix socket 。参数 connectListener 将会作为监听器添加到 'connect' 事件上。返回 'net.Socket'。
net.createConnection(path[, connectListener]) 创建连接到 path 的 unix socket 。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
net.isIP(input) 检测输入的是否为 IP 地址。 IPV4 返回 4, IPV6 返回 6,其他情况返回 0。
net.isIPv4(input) 如果输入的地址为 IPV4, 返回 true,否则返回 false。
net.isIPv6(input) 如果输入的地址为 IPV6, 返回 true,否则返回 false。

》》》net.Server
通常用于创建一个 TCP 或本地服务器

函数 说明
erver.listen(port[, host][, backlog][, callback]) 监听指定端口 port 和 主机 host ac连接。 默认情况下 host 接受任何 IPv4 地址(INADDR_ANY)的直接连接。端口 port 为 0 时,则会分配一个随机端口。
server.listen(path[, callback]) 通过指定 path 的连接,启动一个本地 socket 服务器。
server.listen(handle[, callback]) 通过指定句柄连接。
server.listen(options[, callback]) options 的属性:端口 port, 主机 host, 和 backlog, 以及可选参数 callback 函数, 他们在一起调用server.listen(port, [host], [backlog], [callback])。还有,参数 path 可以用来指定 UNIX socket。
server.close([callback]) 服务器停止接收新的连接,保持现有连接。这是异步函数,当所有连接结束的时候服务器会关闭,并会触发 'close' 事件。
server.address() 操作系统返回绑定的地址,协议族名和服务器端口。
server.unref() 如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。
server.ref() 与 unref 相反,如果这是唯一的服务器,在之前被 unref 了的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。
server.getConnections(callback) 异步获取服务器当前活跃连接的数量。当 socket 发送给子进程后才有效;回调函数有 2 个参数 err 和 count。
事件 说明
listening 当服务器调用 server.listen 绑定后会触发。
connection 当新连接创建后会被触发。socket 是 net.Socket实例。
close 服务器关闭时会触发。注意,如果存在连接,这个事件不会被触发直到所有的连接关闭。
error 发生错误时触发。'close' 事件将被下列事件直接调用。

》》》net.Socket
net.Socket对象是 TCP 或 UNIX Socket 的抽象。
net.Socket 实例实现了一个双工流接口。
他们可以在用户创建客户端(使用 connect())时使用, 或者由 Node 创建它们,并通过 connection 服务器事件传递给用户。

方法 说明
new net.Socket([options]) 构造一个新的 socket 对象。
socket.connect(port[, host][, connectListener]) 指定端口 port 和 主机 host,创建 socket 连接 。参数 host 默认为 localhost。通常情况不需要使用 net.createConnection 打开 socket。只有你实现了自己的 socket 时才会用到。
socket.connect(path[, connectListener]) 打开指定路径的 unix socket。通常情况不需要使用 net.createConnection 打开 socket。只有你实现了自己的 socket 时才会用到。
socket.setEncoding([encoding]) 设置编码
socket.write(data[, encoding][, callback]) 在 socket 上发送数据。第二个参数指定了字符串的编码,默认是 UTF8 编码。
socket.end([data][, encoding]) 半关闭 socket。例如,它发送一个 FIN 包。可能服务器仍在发送数据。
socket.destroy() 确保没有 I/O 活动在这个套接字上。只有在错误发生情况下才需要。(处理错误等等)。
socket.pause() 暂停读取数据。就是说,不会再触发 data 事件。对于控制上传非常有用。
socket.resume() 调用 pause() 后想恢复读取数据。
socket.setTimeout(timeout[, callback]) socket 闲置时间超过 timeout 毫秒后 ,将 socket 设置为超时。
socket.setNoDelay([noDelay]) 禁用纳格(Nagle)算法。默认情况下 TCP 连接使用纳格算法,在发送前他们会缓冲数据。将 noDelay 设置为 true 将会在调用 socket.write() 时立即发送数据。noDelay 默认值为 true。
socket.setKeepAlive([enable][, initialDelay] 禁用/启用长连接功能,并在发送第一个在闲置 socket 上的长连接 probe 之前,可选地设定初始延时。默认为 false。 设定 initialDelay (毫秒),来设定收到的最后一个数据包和第一个长连接probe之间的延时。将 initialDelay 设为0,将会保留默认(或者之前)的值。默认值为0.
socket.address() 操作系统返回绑定的地址,协议族名和服务器端口。返回的对象有 3 个属性,比如{ port: 12346, family: 'IPv4', address: '127.0.0.1' }。
socket.unref() 如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。如果服务器已被 unref,则再次调用 unref 并不会产生影响。
socket.ref() 与 unref 相反,如果这是唯一的服务器,在之前被 unref 了的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。
属性 说明
socket.bufferSize 该属性显示了要写入缓冲区的字节数。
socket.remoteAddress 远程的 IP 地址字符串,例如:'74.125.127.100' or '2001:4860:a005::68'。
socket.remoteFamily 远程IP协议族字符串,比如 'IPv4' or 'IPv6'。
socket.remotePort 远程端口,数字表示,例如:80 or 21。
socket.localAddress 网络连接绑定的本地接口 远程客户端正在连接的本地 IP 地址,字符串表示。例如,如果你在监听'0.0.0.0'而客户端连接在'192.168.1.1',这个值就会是 '192.168.1.1'。
socket.localPort 本地端口地址,数字表示。例如:80 or 21。
socket.bytesRead 接收到得字节数。
socket.bytesWritten 发送的字节数。
事件 说明
ookup 在解析域名后,但在连接前,触发这个事件。对 UNIX sokcet 不适用。
connect 成功建立 socket 连接时触发。
data 当接收到数据时触发。
end 当 socket 另一端发送 FIN 包时,触发该事件。
timeout 当 socket 空闲超时时触发,仅是表明 socket 已经空闲。用户必须手动关闭连接。
drain 当写缓存为空得时候触发。可用来控制上传。
error 错误发生时触发。
close 当 socket 完全关闭时触发。参数 had_error 是布尔值,它表示是否因为传输错误导致 socket 关闭。

例1

============== server.js  ===============
var net = require('net');
var server = net.createServer(function(connection) { 
   console.log('client connected');
   connection.on('end', function() {
      console.log('客户端关闭连接');
   });
   connection.write('Hello World!\r\n');
   connection.pipe(connection);
});
server.listen(8088, function() { 
  console.log('server is listening');
});


============== client.js  ===============
var net = require('net');
var client = net.connect({port: 8088}, function() {
   console.log('连接到服务器!');  
});
client.on('data', function(data) {
   console.log(data.toString());
   client.end();
});
client.on('end', function() { 
   console.log('断开与服务器的连接');
});

============== 在两个终端下分别执行 node server.js、node client.js  ===============
服务端输出
server is listening
client connected
客户端关闭连接


客户端输出
  连接到服务器!
  Hello World!

  断开与服务器的连接
  1. DNS 模块 (解析域名)
引入


var dns = require("dns")
函数 说明
dns.lookup(hostname[, options], callback) 将域名(比如 'runoob.com')解析为第一条找到的记录 A (IPV4)或 AAAA(IPV6)。参数 options可以是一个对象或整数。如果没有提供 options,IP v4 和 v6 地址都可以。如果 options 是整数,则必须是 4 或 6。
dns.lookupService(address, port, callback) 使用 getnameinfo 解析传入的地址和端口为域名和服务。
dns.resolve(hostname[, rrtype], callback) 将一个域名(如 'runoob.com')解析为一个 rrtype 指定记录类型的数组。
dns.resolve4(hostname, callback) 和 dns.resolve() 类似, 仅能查询 IPv4 (A 记录)。 addresses IPv4 地址数组 (比如,['74.125.79.104', '74.125.79.105', '74.125.79.106'])。
dns.resolve6(hostname, callback) 和 dns.resolve4() 类似, 仅能查询 IPv6( AAAA 查询)
dns.resolveMx(hostname, callback) 和 dns.resolve() 类似, 仅能查询邮件交换(MX 记录)。
dns.resolveTxt(hostname, callback) 和 dns.resolve() 类似, 仅能进行文本查询 (TXT 记录)。 addresses 是 2-d 文本记录数组。(比如,[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ])。 每个子数组包含一条记录的 TXT 块。根据使用情况可以连接在一起,也可单独使用。
dns.resolveSrv(hostname, callback) 和 dns.resolve() 类似, 仅能进行服务记录查询 (SRV 记录)。 addresses 是 hostname可用的 SRV 记录数组。 SRV 记录属性有优先级(priority),权重(weight), 端口(port), 和名字(name) (比如,[{'priority': 10, 'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...])。
dns.resolveSoa(hostname, callback) 和 dns.resolve() 类似, 仅能查询权威记录(SOA 记录)。
dns.resolveNs(hostname, callback) 和 dns.resolve() 类似, 仅能进行域名服务器记录查询(NS 记录)。 addresses 是域名服务器记录数组(hostname 可以使用) (比如, ['ns1.example.com', 'ns2.example.com'])。
dns.resolveCname(hostname, callback) 和 dns.resolve() 类似, 仅能进行别名记录查询 (CNAME记录)。addresses 是对 hostname 可用的别名记录数组 (比如,, ['bar.example.com'])。
dns.reverse(ip, callback) 反向解析 IP 地址,指向该 IP 地址的域名数组。
dns.getServers() 返回一个用于当前解析的 IP 地址数组的字符串。
dns.setServers(servers) 指定一组 IP 地址作为解析服务器。
dns.resolve() 方法中有效的 rrtypes值:
    'A' IPV4 地址, 默认
    'AAAA' IPV6 地址
    'MX' 邮件交换记录
    'TXT' text 记录
    'SRV' SRV 记录
    'PTR' 用来反向 IP 查找
    'NS' 域名服务器记录
    'CNAME' 别名记录
    'SOA' 授权记录的初始值
每次 DNS 查询都可能返回以下错误码:

    dns.NODATA: 无数据响应。
    dns.FORMERR: 查询格式错误。
    dns.SERVFAIL: 常规失败。
    dns.NOTFOUND: 没有找到域名。
    dns.NOTIMP: 未实现请求的操作。
    dns.REFUSED: 拒绝查询。
    dns.BADQUERY: 查询格式错误。
    dns.BADNAME: 域名格式错误。
    dns.BADFAMILY: 地址协议不支持。
    dns.BADRESP: 回复格式错误。
    dns.CONNREFUSED: 无法连接到 DNS 服务器。
    dns.TIMEOUT: 连接 DNS 服务器超时。
    dns.EOF: 文件末端。
    dns.FILE: 读文件错误。
    dns.NOMEM: 内存溢出。
    dns.DESTRUCTION: 通道被摧毁。
    dns.BADSTR: 字符串格式错误。
    dns.BADFLAGS: 非法标识符。
    dns.NONAME: 所给主机不是数字。
    dns.BADHINTS: 非法HINTS标识符。
    dns.NOTINITIALIZED: c c-ares 库尚未初始化。
    dns.LOADIPHLPAPI: 加载 iphlpapi.dll 出错。
    dns.ADDRGETNETWORKPARAMS: 无法找到 GetNetworkParams 函数。
    dns.CANCELLED: 取消 DNS 查询。

例1(test.js)

var dns = require('dns');

dns.lookup('www.github.com', function onLookup(err, address, family) {
   console.log('ip 地址:', address);
   dns.reverse(address, function (err, hostnames) {
   if (err) {
      console.log(err.stack);
   }

   console.log('反向解析 ' + address + ': ' + JSON.stringify(hostnames));
});  
});
node test.js输出

ip 地址: 13.250.177.223
反向解析 13.250.177.223: ["ec2-13-250-177-223.ap-southeast-1.compute.amazonaws.com"]
  1. Domain 模块 (捕捉处理try catch无法捕捉的异常)
引入

var domain = require("domain")
Domain 模块分为
    1. 隐式绑定
      把在domain上下文中定义的变量,自动绑定到domain对象
    2. 显式绑定
      把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象

把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象会被通知,不会丢失上下文环境,也不导致程序错误立即退出,与process.on('uncaughtException')不同
函数 说明
domain.run(function) 在域的上下文运行提供的函数,隐式的绑定了所有的事件分发器,计时器和底层请求。
domain.add(emitter) 显式的增加事件
domain.remove(emitter) 删除事件。
domain.bind(callback) 返回的函数是一个对于所提供的回调函数的包装函数。当调用这个返回的函数时,所有被抛出的错误都会被导向到这个域的 error 事件。
domain.intercept(callback) 和 domain.bind(callback) 类似。除了捕捉被抛出的错误外,它还会拦截 Error 对象作为参数传递到这个函数。
domain.enter() 进入一个异步调用的上下文,绑定到domain。
domain.exit() 退出当前的domain,切换到不同的链的异步调用的上下文中。对应domain.enter()。
domain.dispose() 释放一个domain对象,让node进程回收这部分资源。
domain.create() 返回一个domain对象。
属性 说明
domain.members 已加入domain对象的域定时器和事件发射器的数组。

例1(test.js)

var EventEmitter = require("events").EventEmitter;
var domain = require("domain");

var emitter1 = new EventEmitter();
// 创建域
var domain1 = domain.create();
domain1.on('error', function(err){
   console.log("domain1 处理这个错误 ("+err.message+")");
});

// 显式绑定
domain1.add(emitter1);
emitter1.on('error',function(err){
   console.log("监听器处理此错误 ("+err.message+")");
});

emitter1.emit('error',new Error('通过监听器来处理'));
emitter1.removeAllListeners('error');
emitter1.emit('error',new Error('通过 domain1 处理'));

var domain2 = domain.create();
domain2.on('error', function(err){
   console.log("domain2 处理这个错误 ("+err.message+")");
});
// 隐式绑定
domain2.run(function(){
   var emitter2 = new EventEmitter();
   emitter2.emit('error',new Error('通过 domain2 处理'));   
});

domain1.remove(emitter1);
emitter1.emit('error', new Error('转换为异常,系统将崩溃!'));
node test.js输出

监听器处理此错误 (通过监听器来处理)
domain1 处理这个错误 (通过 domain1 处理)
domain2 处理这个错误 (通过 domain2 处理)
events.js:298
      throw er; // Unhandled 'error' event
      ^

Error: 转换为异常,系统将崩溃!
    at Object. (/Users/cx/Desktop/nodejs/client.js:40:24)
    at Module._compile (internal/modules/cjs/loader.js:1151:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)
    at Module.load (internal/modules/cjs/loader.js:1000:32)
    at Function.Module._load (internal/modules/cjs/loader.js:899:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
Emitted 'error' event at:
    at Object. (/Users/cx/Desktop/nodejs/client.js:40:10)
    at Module._compile (internal/modules/cjs/loader.js:1151:30)
    [... lines matching original stack trace ...]
    at internal/main/run_main_module.js:17:47
  1. util 模块(Node.js核心)常用函数
引入

const util = require('util');

将 async 异步函数(或者一个返回值为 Promise 的函数)转换成遵循异常优先的回调风格的函数

// (err, value) => ... 回调,作为最后一个参数
// 在回调函数中,第一个参数为拒绝的原因(如果 Promise 解决,则为 null),第二个参数则是解决的值。
util.callbackify(original)
例1

const util = require('util');

async function fn() {
  return 'hello world';
}
const callbackFunction = util.callbackify(fn);

callbackFunction((err, ret) => {
  if (err) throw err;
  console.log(ret);
});


输出
hello world
例2

function fn() {
  return Promise.reject(null);
}
const callbackFunction = util.callbackify(fn);

callbackFunction((err, ret) => {
  // 当 Promise 被以 `null` 拒绝时,它被包装为 Error 并且原始值存储在 `reason` 中。
  err && err.hasOwnProperty('reason') && err.reason === null;  // true
});

实现对象间原型继承的函数

util.inherits(constructor, superConstructor)

JavaScript 的面向对象特性是基于原型的,与常见的基于类的不同。JavaScript 没有提供对象继承的语言级别特性,而是通过原型复制来实现的。
例

============= test.js =============
var util = require('util'); 
function Base() { 
    this.name = 'cx'; 
    this.base = 2000; 
    this.sayHello = function() { 
    console.log('Hello ' + this.name); 
    }; 
} 
Base.prototype.showName = function() { 
    console.log(this.name);
}; 
function Sub() { 
    this.name = 'sub'; 
} 
util.inherits(Sub, Base); 
var objBase = new Base(); 
objBase.showName(); 
objBase.sayHello(); 
console.log(objBase); 
var objSub = new Sub(); 
objSub.showName(); 
//objSub.sayHello(); 
console.log(objSub); 
=============终端输出=============
cx
Hello cx
Base { name: 'cx', base: 2000, sayHello: [Function (anonymous)] }
sub
Sub { name: 'sub' }

=============注意=============
Sub 仅仅继承了Base 在原型中定义的函数,而构造函数内部创造的 base 属 性和 sayHello 函数都没有被 Sub 继承。
在原型中定义的属性不会被 console.log 作 为对象的属性输出。

将任意对象转换为字符串

// object 要转换的对象
// showHidden 是否显示隐藏信息
// depth 最大递归的层数,默认2层,null则表示不限递归层数完整遍历
// colors 以 ANSI 颜色编码,在终端显示更漂亮
util.inspect(object,[showHidden],[depth],[colors])
例

============= test.js =============
var util = require('util'); 
function Person() { 
    this.name = 'cx'; 
    this.toString = function() { 
    return this.name; 
    }; 
} 
var obj = new Person(); 
console.log(util.inspect(obj)); 
console.log(util.inspect(obj, true)); 

=============终端输出=============
Person { name: 'cx', toString: [Function (anonymous)] }
Person {
  name: 'cx',
  toString:  [Function (anonymous)] {
    [length]: 0,
    [name]: '',
    [arguments]: null,
    [caller]: null,
    [prototype]: { [constructor]: [Circular *1] }
  }
}

是否是数组

util.isArray(object)
例

var util = require('util');
// true
util.isArray([])
// true 
util.isArray(new Array)
// false 
util.isArray({})

是否是正则表达式

util.isRegExp(object)
例

var util = require('util');
// true
util.isRegExp(/some regexp/)
// true
util.isRegExp(new RegExp('another regexp'))
// false 
util.isRegExp({})

是否是日期

util.isDate(object)
例

var util = require('util');
// true
util.isDate(new Date())
// false (without 'new' returns a String)
util.isDate(Date())
// false  
util.isDate({})

Web 模块

Node.js 提供了 http 模块。http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块。
var http = require('http');

  1. Web应用架构

Web服务器,目前最主流的3个: Apache、Nginx、IIS

Web应用架构
Web应用架构说明
  1. Client 
    客户端,一般指浏览器。浏览器可以通过 HTTP 协议向服务器请求数据。
  2. Server 
    服务端,一般指 Web 服务器。可以接收客户端请求,并向客户端发送响应数据。
  3. Business 
    业务层, 通过 Web 服务器处理应用程序,如与数据库交互,逻辑运算,调用外部程序等。
  4. Data 
    数据层,一般由数据库组成。

index.html





Hello World


    

我的第一个标题

我的第一个段落。

server.js 服务器 (同一目录下创建该文件)

var http = require('http');
var fs = require('fs');
var url = require('url');
 
 
// 创建服务器
http.createServer( function (request, response) {  
   // 解析请求,包括文件名
   var pathname = url.parse(request.url).pathname;
   
   // 输出请求的文件名
   console.log("Request for " + pathname + " received.");
   
   // 从文件系统中读取请求的文件内容
   fs.readFile(pathname.substr(1), function (err, data) {
      if (err) {
         console.log(err);
         // HTTP 状态码: 404 : NOT FOUND
         // Content Type: text/html
         response.writeHead(404, {'Content-Type': 'text/html'});
      }else{             
         // HTTP 状态码: 200 : OK
         // Content Type: text/html
         response.writeHead(200, {'Content-Type': 'text/html'});    
         
         // 响应文件内容
         response.write(data.toString());        
      }
      //  发送响应数据
      response.end();
   });   
}).listen(8088);
 
// 控制台会输出以下信息
console.log('Server running at http://127.0.0.1:8088/');

终端启动服务器:node server.js

浏览器输入http://127.0.0.1:8088/index.html

终端输出:Request for /index.html received.

client.js 客户端

var http = require('http');
 
// 用于请求的选项
var options = {
   host: 'localhost',
   port: '8088',
   path: '/index.html'  
};
 
// 处理响应的回调函数
var callback = function(response){
   // 不断更新数据
   var body = '';
   response.on('data', function(data) {
      body += data;
   });
   
   response.on('end', function() {
      // 数据接收完成
      console.log(body);
   });
}
// 向服务端发送请求
var req = http.request(options, callback);
req.end();

执行客户端:node client.js(新开一个终端)

服务端-终端会输出:
Request for /index.html received.

客户端-终端会输出html内容:




Hello World


    

我的第一个标题

我的第一个段落。

GET/POST请求

  1. 获取GET请求内容

server.js

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);

node server.js

浏览器输入http://localhost:3000/user?name=cx&hello

server.js

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain'});
 
    // 解析 url 参数
    var params = url.parse(req.url, true).query;
    res.write("name=" + params.name);
    res.write("\n");
    res.write("hello=" + params.hello);
    res.end();
 
}).listen(3000);

node server.js


浏览器输入hhttp://localhost:3000/user?name=cx&hello=world
  1. 获取POST请求内容
 POST 请求的内容全部的都在请求体中,http.ServerRequest 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作。

比如上传文件,而很多时候我们可能并不需要理会请求体的内容,恶意的POST请求会大大消耗服务器的资源,所以 node.js 默认是不会解析请求体的,当你需要的时候,需要手动来做。

var http = require('http');
var querystring = require('querystring');
var util = require('util');
 
http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
 
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);

例1(server.js)

var http = require('http');
var querystring = require('querystring');
 
var postHTML = 
  'Hello World' +
  '' +
  '
' + '网站名:
' + '网站 URL:
' + '' + '
' + ''; http.createServer(function (req, res) { var body = ""; req.on('data', function (chunk) { body += chunk; }); req.on('end', function () { // 解析参数 body = querystring.parse(body); // 设置响应头部信息及编码 res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'}); if(body.name && body.url) { // 输出提交的数据 res.write("网站名:" + body.name); res.write("
"); res.write("网站 URL:" + body.url); } else { // 输出表单 res.write(postHTML); } res.end(); }); }).listen(3000);

node server.js


浏览器输入http://localhost:3000
提交结果

多进程

引入

const child_process = require('child_process');
Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于在多核 cpu 的系统上创建多个子进程,从而提高性能。
每个子进程总是带有三个流对象:child.stdin,child.stdout 和child.stderr。他们可能会共享父进程的 stdio 流,或者也可以是独立的被导流的流对象。
  1. child_process.exec(command[, options], callback)

使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回
等待进程结束,一次性返回缓冲区的内容

command
  将要执行的命令
  是个字符串,参数使用空格隔开(例:'node support.js ')

options 
  参数
  是个对象
    1. cwd 
      子进程的当前工作目录
      字符串
    2. env 
      环境变量键值对
      对象
    3. encoding
      字符编码(默认: 'utf8')
      字符串
    4. shell
      将要执行命令的 Shell(默认: 在 UNIX 中为/bin/sh, 在 Windows 中为cmd.exe, Shell 应当能识别 -c开关在 UNIX 中,或 /s /c 在 Windows 中。 在Windows 中,命令行解析应当能兼容cmd.exe)
      字符串
    5. timeout
      超时时间(默认: 0)
      数字
    6. maxBuffer
      在 stdout 或 stderr 中允许存在的最大缓冲(二进制),如果超出那么子进程将会被杀死 (默认: 200*1024)
      数字
    7. killSignal 
      结束信号(默认:'SIGTERM')
      字符串
    8. uid
      设置用户进程的 ID
      数字
    9. gid
      设置进程组的 ID
      数字

callback 
  回调函数
  包含三个参数error, stdout 和 stderr。(例:function (error, stdout, stderr) {} )

例1

================ support.js  ================
console.log("进程 " + process.argv[2] + " 执行。" );

================ test.js ================
const fs = require('fs');
const child_process = require('child_process');
 
for(var i=0; i<3; i++) {
    var workerProcess = child_process.exec('node support.js '+i, function (error, stdout, stderr) {
        if (error) {
            console.log(error.stack);
            console.log('Error code: '+error.code);
            console.log('Signal received: '+error.signal);
        }
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
    });
 
    workerProcess.on('exit', function (code) {
        console.log('子进程已退出,退出码 '+code);
    });
}

================ node test.js ================
子进程已退出,退出码 0
子进程已退出,退出码 0
子进程已退出,退出码 0
stdout: 进程 2 执行。

stderr: 
stdout: 进程 1 执行。

stderr: 
stdout: 进程 0 执行。

stderr: 
  1. child_process.spawn(command[, args][, options])

使用指定的命令行参数创建新进程
返回流 (stdout & stderr),在进程返回大量数据时使用。进程一旦开始执行时 spawn() 就开始接收响应。

command
  将要执行的命令
  是个字符串
args
  字符串参数数组
  是个Array 

options 
    是个Object
    1. cwd 
      子进程的当前工作目录
      String 
    2. env  
      环境变量键值对
      Object
    3. stdio  
      子进程的 stdio 配置
      Array|String
    4. detached  
      这个子进程将会变成进程组的领导
      Boolean
    5. uid 
      设置用户进程的 ID
      Number
    6. gid  
      设置进程组的 ID
      Number

例1

================ support.js  ================
console.log("进程 " + process.argv[2] + " 执行。" );

================ test.js ================
const fs = require('fs');
const child_process = require('child_process');
 
for(var i=0; i<3; i++) {
   var workerProcess = child_process.spawn('node', ['support.js', i]);
 
   workerProcess.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
   });
   workerProcess.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
   });
   workerProcess.on('close', function (code) {
      console.log('子进程已退出,退出码 '+code);
   });
}

================ node test.js ================
stdout: 进程 0 执行。

stdout: 进程 1 执行。

stdout: 进程 2 执行。

子进程已退出,退出码 0
子进程已退出,退出码 0
子进程已退出,退出码 0
  1. child_process.fork(modulePath[, args][, options])

spawn() 方法的特殊形式,用于创建进程。
如 fork('./son.js') 相当于 spawn('node', ['./son.js']) 。
与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信

modulePath
  将要在子进程中运行的模块
  String

args
  字符串参数数组
  Array

options
  Object
    1. cwd  
      子进程的当前工作目录
      String
    2. env  
      环境变量键值对
      Object
    3. execPath  
      创建子进程的可执行文件
      String
    4. execArgv  
      子进程的可执行文件的字符串参数数组(默认: process.execArgv)
      Array
    5. silent  
      如果为true,子进程的stdin,stdout和stderr将会被关联至父进程,
      如果为false,它们将会从父进程中继承。(默认为:false)
      Boolean
    6. uid  
      设置用户进程的 ID
      Number
    7. gid  
      设置进程组的 ID
      Number
================ support.js  ================
console.log("进程 " + process.argv[2] + " 执行。" );

================ test.js ================
const fs = require('fs');
const child_process = require('child_process');
 
for(var i=0; i<3; i++) {
   var worker_process = child_process.fork("support.js", [i]);    

   worker_process.on('close', function (code) {
      console.log('子进程已退出,退出码 ' + code);
   });
}

================ node test.js ================
进程 0 执行。
进程 1 执行。
进程 2 执行。
子进程已退出,退出码 0
子进程已退出,退出码 0
子进程已退出,退出码 0

JXcore(打包)

JXcore:一个支持多线程的Node.js发行版本

  1. 安装JXcore

JXcore安装包github地址

1. 下载JXcore安装包
2. 解压后找到对应平台的zip包,解压后将jx可执行文件复制到/usr/local/bin目录下
3. export PATH=$PATH:/usr/local/bin
4. 查看是否安装成功(出现jx版本号,则成功) 
  jx --version
  1. 将项目打包成一个可运行的.jx文件
打包(指定 index.js 为 Node.js 项目的主文件)
  jx package index.js index

会生成2文件
  1. index.jxp。中间件文件,包含了需要编译的完整项目信息。
  2. index.jx。完整包信息的二进制文件,可运行在客户端上。

运行
  jx index.jx

Buffer(缓冲区)

JavaScript只有字符串数据类型,没有二进制数据类型。
但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。
Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。
原始数据存储在 Buffer 类的实例中。
一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

在v6.0之前创建Buffer对象直接使用new Buffer()构造函数来创建对象实例,但是Buffer对内存的权限操作相比很大,可以直接捕获一些敏感信息,所以在v6.0以后,官方文档里面建议使用 Buffer.from() 接口去创建Buffer对象。
  1. Buffer 与字符编码

Buffer实例一般用于表示编码字符的序列,比如 UTF-8 、 UCS2 、 Base64 、或十六进制编码的数据。
通过使用显式的字符编码,就可以在 Buffer 实例与普通的 JavaScript 字符串之间进行相互转换。

Node.js 目前支持的字符编码包括:
  1. ascii 
    仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
  2. utf8 
    多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
  3. utf16le 
    2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
  4. ucs2 
    utf16le 的别名。
  5. base64 
    Base64 编码。
  6. latin1  
    一种把 Buffer 编码成一字节编码的字符串的方式。
  7. binary 
    latin1 的别名。
  8. hex 
    将每个字节编码为两个十六进制字符

例1

const buf = Buffer.from('cx', 'ascii');

// 输出 6378
console.log(buf.toString('hex'));

// 输出 Y3g=
console.log(buf.toString('base64'));
  1. 创建 Buffer 类
Buffer.alloc(size[, fill[, encoding]])
    返回一个指定大小的 Buffer 实例,如果没有设置 fill,则默认填满 0
Buffer.allocUnsafe(size)
    返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据
Buffer.allocUnsafeSlow(size)
Buffer.from(array)
    返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
Buffer.from(arrayBuffer[, byteOffset[, length]])
    返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
Buffer.from(buffer)
    复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
Buffer.from(string[, encoding])
    返回一个被 string 的值初始化的新的 Buffer 实例

例1

// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);

// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1);

// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);

// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);

// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');

// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');
  1. 写入缓冲区
buf.write(string[, offset[, length]][, encoding])

根据 encoding 的字符编码写入 string 到 buf 中的 offset 位置。 
length 参数是写入的字节数。 如果 buf 没有足够的空间保存整个字符串,则只会写入 string 的一部分。 只部分解码的字符不会被写入。
返回实际写入的大小。如果 buffer 空间不足, 则只会写入部分字符串。
参数说明

  1. string 
    写入缓冲区的字符串。
  2. offset 
    缓冲区开始写入的索引值,默认为 0 。
  3. length 
    写入的字节数,默认为 buffer.length
  4. encoding 
    使用的编码。默认为 'utf8' 。

例1

buf = Buffer.alloc(256);
len = buf.write("www.baidu.com");

console.log("写入字节数 : "+  len);

================
写入字节数 : 13
  1. 从缓冲区读取数据
buf.toString([encoding[, start[, end]]])

解码缓冲区数据并使用指定的编码返回字符串。
参数说明

  1. encoding 
    使用的编码。默认为 'utf8' 。
  2. start 
    指定开始读取的索引位置,默认为 0。
  3. end 
    结束位置,默认为缓冲区的末尾。

例1

buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
  buf[i] = i + 97;
}

console.log( buf.toString('ascii'));       // 输出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5));   //使用 'ascii' 编码, 并输出: abcde
console.log( buf.toString('utf8',0,5));    // 使用 'utf8' 编码, 并输出: abcde
console.log( buf.toString(undefined,0,5)); // 使用默认的 'utf8' 编码, 并输出: abcde

================
abcdefghijklmnopqrstuvwxyz
abcde
abcde
abcde
  1. 将 Buffer 转换为 JSON 对象
buf.toJSON()

当字符串化一个 Buffer 实例时,JSON.stringify() 会隐式地调用该 toJSON()。

例1

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);

// 输出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);

const copy = JSON.parse(json, (key, value) => {
  return value && value.type === 'Buffer' ?
    Buffer.from(value.data) :
    value;
});

// 输出: 
console.log(copy);
==================

{"type":"Buffer","data":[1,2,3,4,5]}

  1. 缓冲区合并
Buffer.concat(list[, totalLength])

返回一个多个成员合并的新 Buffer 对象
参数说明

  1. list 
    用于合并的 Buffer 对象数组列表。
  2. totalLength 
    指定合并后Buffer对象的总长度。

例1

var buffer1 = Buffer.from(('hello'));
var buffer2 = Buffer.from(('world'));
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("buffer3 内容: " + buffer3.toString());
=====================
buffer3 内容: helloworld
  1. 缓冲区比较
buf.compare(otherBuffer);
返回一个数字,表示 buf 在 otherBuffer 之前,之后或相同。
参数说明

  1. otherBuffer 
    与 buf 对象比较的另外一个 Buffer 对象。 

例1

var buffer1 = Buffer.from('ABC');
var buffer2 = Buffer.from('ABCD');
var result = buffer1.compare(buffer2);

if(result < 0) {
   console.log(buffer1 + " 在 " + buffer2 + "之前");
}else if(result == 0){
   console.log(buffer1 + " 与 " + buffer2 + "相同");
}else {
   console.log(buffer1 + " 在 " + buffer2 + "之后");
}
======================
ABC 在 ABCD之前
  1. 拷贝缓冲区
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
参数说明

  1. targetBuffer 
    要拷贝的 Buffer 对象。
  2. targetStart 
    数字, 可选, 默认: 0
  3. sourceStart 
    数字, 可选, 默认: 0
  4. sourceEnd 
    数字, 可选, 默认: buffer.length

例1

var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('RUNOOB');

//将 buf2 插入到 buf1 指定位置上
buf2.copy(buf1, 2);

console.log(buf1.toString());

===================
abRUNOOBijkl
  1. 缓冲区裁剪
buf.slice([start[, end]])

返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引 start 到 end 的位置剪切。
参数说明

  1. start 
    数字, 可选, 默认: 0
  2. end 
    数字, 可选, 默认: buffer.length

例1

var buffer1 = Buffer.from('runoob');
// 剪切缓冲区
var buffer2 = buffer1.slice(0,2);
console.log("buffer2 content: " + buffer2.toString());
==================
buffer2 content: ru
  1. 缓冲区长度
buf.length;

返回 Buffer 对象所占据的内存长度

例1

var buffer = Buffer.from('hello world');
//  缓冲区长度
console.log("buffer length: " + buffer.length);
==================
buffer length: 11
方法 说明
new Buffer(size) 分配一个新的 size 大小单位为8位字节的 buffer。 注意, size 必须小于 kMaxLength,否则,将会抛出异常 RangeError。废弃的: 使用 Buffer.alloc() 代替(或 Buffer.allocUnsafe())。
new Buffer(buffer) 拷贝参数 buffer 的数据到 Buffer 实例。废弃的: 使用 Buffer.from(buffer) 代替。
new Buffer(str[, encoding]) 分配一个新的 buffer ,其中包含着传入的 str 字符串。 encoding 编码方式默认为 'utf8'。 废弃的: 使用 Buffer.from(string[, encoding]) 代替。
buf.length 返回这个 buffer 的 bytes 数。注意这未必是 buffer 里面内容的大小。length 是 buffer 对象所分配的内存数,它不会随着这个 buffer 对象内容的改变而改变。
buf.write(string[, offset[, length]][, encoding]) 根据参数 offset 偏移量和指定的 encoding 编码方式,将参数 string 数据写入buffer。 offset 偏移量默认值是 0, encoding 编码方式默认是 utf8。 length 长度是将要写入的字符串的 bytes 大小。 返回 number 类型,表示写入了多少 8 位字节流。如果 buffer 没有足够的空间来放整个 string,它将只会只写入部分字符串。 length 默认是 buffer.length - offset。 这个方法不会出现写入部分字符。
buf.writeUIntLE(value, offset, byteLength[, noAssert]) 将 value 写入到 buffer 里, 它由 offset 和 byteLength 决定,最高支持 48 位无符号整数,小端对齐。noAssert 值为 true 时,不再验证 value 和 offset 的有效性。 默认是 false。
buf.writeUIntBE(value, offset, byteLength[, noAssert]) 将 value 写入到 buffer 里, 它由 offset 和 byteLength 决定,最高支持 48 位无符号整数,大端对齐。noAssert 值为 true 时,不再验证 value 和 offset 的有效性。 默认是 false。
buf.writeIntLE(value, offset, byteLength[, noAssert]) 将value 写入到 buffer 里, 它由offset 和 byteLength 决定,最高支持48位有符号整数,小端对齐。noAssert 值为 true 时,不再验证 value 和 offset 的有效性。 默认是 false。
buf.writeIntBE(value, offset, byteLength[, noAssert]) 将value 写入到 buffer 里, 它由offset 和 byteLength 决定,最高支持48位有符号整数,大端对齐。noAssert 值为 true 时,不再验证 value 和 offset 的有效性。 默认是 false。
buf.readUIntLE(offset, byteLength[, noAssert]) 支持读取 48 位以下的无符号数字,小端对齐。noAssert 值为 true 时, offset 不再验证是否超过 buffer 的长度,默认为 false。
buf.readUIntBE(offset, byteLength[, noAssert]) 支持读取 48 位以下的无符号数字,大端对齐。noAssert 值为 true 时, offset 不再验证是否超过 buffer 的长度,默认为 false。
buf.readIntLE(offset, byteLength[, noAssert]) 支持读取 48 位以下的有符号数字,小端对齐。noAssert 值为 true 时, offset 不再验证是否超过 buffer 的长度,默认为 false。
buf.readIntBE(offset, byteLength[, noAssert]) 支持读取 48 位以下的有符号数字,大端对齐。noAssert 值为 true 时, offset 不再验证是否超过 buffer 的长度,默认为 false。
buf.toString([encoding[, start[, end]]]) 根据 encoding 参数(默认是 'utf8')返回一个解码过的 string 类型。还会根据传入的参数 start (默认是 0) 和 end (默认是 buffer.length)作为取值范围。
buf.toJSON() 将 Buffer 实例转换为 JSON 对象。
buf[index] 获取或设置指定的字节。返回值代表一个字节,所以返回值的合法范围是十六进制0x00到0xFF 或者十进制0至 255。
buf.equals(otherBuffer) 比较两个缓冲区是否相等,如果是返回 true,否则返回 false。
buf.compare(otherBuffer) 比较两个 Buffer 对象,返回一个数字,表示 buf 在 otherBuffer 之前,之后或相同。
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]]) buffer 拷贝,源和目标可以相同。 targetStart 目标开始偏移和 sourceStart 源开始偏移默认都是 0。 sourceEnd 源结束位置偏移默认是源的长度 buffer.length 。
buf.slice([start[, end]]) 剪切 Buffer 对象,根据 start(默认是 0 ) 和 end (默认是 buffer.length ) 偏移和裁剪了索引。 负的索引是从 buffer 尾部开始计算的。
buf.readUInt8(offset[, noAssert]) 根据指定的偏移量,读取一个无符号 8 位整数。若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 如果这样 offset 可能会超出buffer 的末尾。默认是 false。
buf.readUInt16LE(offset[, noAssert]) 根据指定的偏移量,使用特殊的 endian 字节序格式读取一个无符号 16 位整数。若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出 buffer 的末尾。默认是 false。
buf.readUInt16BE(offset[, noAssert]) 根据指定的偏移量,使用特殊的 endian 字节序格式读取一个无符号 16 位整数,大端对齐。若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出 buffer 的末尾。默认是 false。
buf.readUInt32LE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个无符号 32 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.readUInt32BE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个无符号 32 位整数,大端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.readInt8(offset[, noAssert]) 根据指定的偏移量,读取一个有符号 8 位整数。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出 buffer 的末尾。默认是 false。
buf.readInt16LE(offset[, noAssert]) 根据指定的偏移量,使用特殊的 endian 格式读取一个 有符号 16 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出 buffer 的末尾。默认是 false。
buf.readInt16BE(offset[, noAssert]) 根据指定的偏移量,使用特殊的 endian 格式读取一个 有符号 16 位整数,大端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出 buffer 的末尾。默认是 false。
buf.readInt32LE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个有符号 32 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.readInt32BE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个有符号 32 位整数,大端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.readFloatLE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个 32 位双浮点数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer的末尾。默认是 false。
buf.readFloatBE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian 字节序格式读取一个 32 位双浮点数,大端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer的末尾。默认是 false。
buf.readDoubleLE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian字节序格式读取一个 64 位双精度数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.readDoubleBE(offset[, noAssert]) 根据指定的偏移量,使用指定的 endian字节序格式读取一个 64 位双精度数,大端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
buf.writeUInt8(value, offset[, noAssert]) 根据传入的 offset 偏移量将 value 写入 buffer。注意:value 必须是一个合法的无符号 8 位整数。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则不要使用。默认是 false。
buf.writeUInt16LE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的无符号 16 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出buffer的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeUInt16BE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的无符号 16 位整数,大端对齐。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出buffer的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeUInt32LE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式(LITTLE-ENDIAN:小字节序)将 value 写入buffer。注意:value 必须是一个合法的无符号 32 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着value 可能过大,或者offset可能会超出buffer的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeUInt32BE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式(Big-Endian:大字节序)将 value 写入buffer。注意:value 必须是一个合法的有符号 32 位整数。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者offset可能会超出buffer的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeInt8(value, offset[, noAssert])
buf.writeInt16LE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的 signed 16 位整数。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false 。
buf.writeInt16BE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的 signed 16 位整数。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false 。
buf.writeInt32LE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的 signed 32 位整数。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeInt32BE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个合法的 signed 32 位整数。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeFloatLE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer 。注意:当 value 不是一个 32 位浮点数类型的值时,结果将是不确定的。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeFloatBE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer 。注意:当 value 不是一个 32 位浮点数类型的值时,结果将是不确定的。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value可能过大,或者 offset 可能会超出 buffer 的末尾从而造成 value 被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeDoubleLE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个有效的 64 位double 类型的值。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成value被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.writeDoubleBE(value, offset[, noAssert]) 根据传入的 offset 偏移量和指定的 endian 格式将 value 写入 buffer。注意:value 必须是一个有效的 64 位double 类型的值。 若参数 noAssert 为 true 将不会验证 value 和 offset 偏移量参数。 这意味着 value 可能过大,或者 offset 可能会超出 buffer 的末尾从而造成value被丢弃。 除非你对这个参数非常有把握,否则尽量不要使用。默认是 false。
buf.fill(value[, offset][, end]) 使用指定的 value 来填充这个 buffer。如果没有指定 offset (默认是 0) 并且 end (默认是 buffer.length) ,将会填充整个buffer。
const buf = Buffer.allocUnsafe(6);
buf.writeUIntLE(0x1234567890ab, 0, 6);
// 输出: 
console.log(buf);
const buf = Buffer.allocUnsafe(6);
buf.writeUIntBE(0x1234567890ab, 0, 6);
// 输出: 
console.log(buf);

待续。。。。。

你可能感兴趣的:(Node.js了解)