Node.js Domain(域) 简化异步代码的异常处理,可以捕捉处理try catch无法捕捉的异常。
var domain = require("domain")
domain模块,把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象会被通知,不会丢失上下文环境,也不导致程序错误立即退出,与process.on(‘uncaughtException’)不同。
Domain 模块可分为隐式绑定和显式绑定:
方法 | 描述 |
---|---|
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对象的域定时器和事件发射器的数组。 |
main.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 main.js
//输出
// 监听器处理此错误 (通过监听器来处理)
// domain1 处理这个错误 (通过 domain1 处理)
// domain2 处理这个错误 (通过 domain2 处理)
// node:events:491
// throw er; // Unhandled 'error' event
// ^
// Error: 转换为异常,系统将崩溃!
// at Object. (D:\test\temp1.cjs:28:24)
// at Module._compile (node:internal/modules/cjs/loader:1254:14)
// at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
// at Module.load (node:internal/modules/cjs/loader:1117:32)
// at Module._load (node:internal/modules/cjs/loader:958:12)
// at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
// at node:internal/main/run_main_module:23:47
Node.js DNS 模块用于解析域名
var dns = require("dns")
方法 | 描述 |
---|---|
dns.lookup(hostname[, options], callback) | 将域名(比如 xxx.com)解析为第一条找到的记录 A (IPV4)或 AAAA(IPV6)。options可以是一个对象或整数。如果没有提供 options,IP v4 和 v6 地址都可以。如果 options 是整数,则必须是 4 或 6。 |
dns.lookupService(address, port, callback) | 使用 getnameinfo 解析传入的地址和端口为域名和服务。 |
dns.resolve(hostname[, rrtype], callback) | 将一个域名(如 xxxx.com)解析为一个 rrtype 指定记录类型的数组 |
dns.resolve4(hostname, callback) | 和 dns.resolve() 类似, 仅能查询 IPv4 (A 记录)。 addresses IPv4 地址数组 (比如,[74.125.79.104, 74.125.79.105]) |
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值:
DNS 查询返回的错误码:
main.js
var dns = require("dns");
dns.lookup("echarts.apache.org", 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 main.js
//输出
// ip 地址: 151.101.2.132
// Error: getHostByAddr ENOTFOUND 151.101.2.132
// at QueryReqWrap.onresolve [as oncomplete] (node:internal/dns/callback_resolver:47:19)
// 反向解析 151.101.2.132: undefined
Node.js 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) | 检测input是否为 IP 地址.IPV4 返回 4,IPV6 返回 6,其他情况返回 0 |
net.isIPv4(input) | 如果input地址为 IPV4,返回 true,否则false |
net.isIPv6(input) | 如果input地址为 IPV6,返回 true,否则false |
net.Server通常用于创建一个 TCP 或本地服务器:
方法 | 描述 |
---|---|
server.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 对象是 TCP 或 UNIX Socket 的抽象。net.Socket 实例实现了一个双工流接口。可以在用户创建客户端(使用 connect())时使用, 或者由 Node 创建它们,并通过 connection 服务器事件传递给用户
事件 | 描述 |
---|---|
lookup | 在解析域名后,但在连接前,触发该事件。对 UNIX sokcet 不适用 |
connect | 成功建立 socket 连接时触发 |
data | 当接收到数据时触发 |
end | 当 socket 另一端发送 FIN 包时,触发 |
timeout | 当 socket 空闲超时时触发,仅表明 socket 已经空闲。用户必须手动关闭连接 |
drain | 当写缓存为空得时候触发。可用来控制上传 |
error | 错误发生时触发 |
close | 当 socket 完全关闭时触发。参数 had_error 是布尔值,它表示是否因为传输错误导致 socket 关闭 |
net.Socket 提供了很多有用的属性,便于控制 socket 交互:
属性 | 描述 |
---|---|
socket.bufferSize | 该属性显示了要写入缓冲区的字节数 |
socket.remoteAddress | 远程的 IP 地址字符串,例如:74.125.127.100/2001:4860:a005::68。 |
socket.remoteFamily | 远程IP协议族字符串,比如 IPv4/IPv6 |
socket.remotePort | 远程端口,数字表示,例如:80/21 |
socket.localAddress | 网络连接绑定的本地接口 远程客户端正在连接的本地 IP 地址,字符串表示。例如,如果你在监听0.0.0.0而客户端连接在192.168.1.1,这个值就会是192.168.1.1 |
socket.localPort | 本地端口地址,数字表示。例如:80/21 |
socket.bytesRead | 接收到得字节数 |
socket.bytesWritten | 发送的字节数 |
属性 | 描述 |
---|---|
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 并不会产生影响 |
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(8080, function () {
console.log("server is listening");
});
//终端执行 node server.js
//输出
// server is listening
client.js 文件:
var net = require("net");
var client = net.connect({ port: 8080 }, function () {
console.log("连接到服务器!");
});
client.on("data", function (data) {
console.log(data.toString());
client.end();
});
client.on("end", function () {
console.log("断开与服务器的连接");
});
//终端执行 node main.js
//输出
// 连接到服务器!
// Hello World!
// 断开与服务器的连接
提供基本的系统操作函数,主要是用于处理与操作系统相关的功能模块
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的属性:
main.js 文件:
var os = require("os");
console.log("endianness : " + os.endianness()); // CPU 的字节序
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 main.js
//输出
// endianness : LE
// type : Windows_NT
// platform : win32
// Total memory : 17015451648 bytes.
// Free memory : 5720956928 bytes.
是Node.js的核心模块,提供了一些常用函数的合集,弥补javascript功能过于精简的问题
const util = require('util');
util.callbackify(original) 将 async 异步函数(或者返回值为 Promise 的函数)转换成遵循异常优先
的回调风格
的函数.例如将 (err, value) => … 回调作为最后一个参数。 在回调中,err为拒绝(Promise reject)的原因(若Promise resolve,则err为 null),value则是解决的值。
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
回调函数是异步执行的,并且有异常堆栈错误追踪。 如果回调函数抛出一个异常,进程会触发一个 ‘uncaughtException’ 异常,如果没有被捕获,进程将会退出。
null 在回调函数中作为一个参数有其特殊的意义,如果回调函数的首个参数为 Promise 拒绝的原因且带有返回值,且值可以转换成布尔值 false,这个值会被封装在 Error 对象里,可以通过属性 reason 获取。
function fn() {
return Promise.reject(null);
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, ret) => {
//Promise 被以 `null` reject时,被包装为Error并且原始值存储在 `reason` 中
err && err.hasOwnProperty('reason') && err.reason === null; // true
});
original 为 async 异步函数,该函数返回传统回调函数。
util.inherits(constructor, superConstructor) 是一个实现对象间原型继承的函数。已经废弃。
JavaScript 的面向对象特性是基于原型的,与常见的基于类的不同。JavaScript 没有提供对象继承的语言级别特性,而是通过原型复制来实现的。所以constructor继承superConstructor的原型
var util = require('util');
function Base() {
this.name = 'base';
this.base = 1991;
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(); //base
objBase.sayHello(); //Hello base
console.log(objBase); //Base { name: 'base', base: 1991, sayHello: [Function (anonymous)] }
var objSub = new Sub();
objSub.showName(); //sub
//objSub.sayHello();
console.log(objSub); //Sub { name: 'sub' }
定义的基础对象 Base 和一个继承 Base 的 Sub,Base 有三个在构造函数内定义的属性和一个原型中定义的函数,通过util.inherits 实现继承。运行结果请查看上述注释
注意:Sub 仅仅继承了 Base 在原型中定义的函数,而Base构造函数内部创造的属性和函数都没有被 Sub 继承。
所以如果去掉 objSub.sayHello(); 这行的注释就会报错:TypeError: objSub.sayHello is not a function
在原型中定义的属性不会被 console.log 作为对象的属性输出
。
因为当前继承方式已废弃,现有继承方法:
class Base {
name = "base";
base = 1991;
sayHello = function () {
console.log("Hello " + this.name);
};
}
Base.prototype.showName = function () {
console.log(this.name);
};
class Sub extends Base {
name = "sub";
}
var objBase = new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
var objSub = new Sub();
objSub.showName();
objSub.sayHello();
console.log(objSub);
//输出:
// base
// Hello base
// Base { name: 'base', base: 1991, sayHello: [Function: sayHello] }
// sub
// Hello sub
// Sub { name: 'sub', base: 1991, sayHello: [Function: sayHello] }
extends 方式,不论是原型还是构造函数中的属性与方法均继承
util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法,通常用于调试和错误输出。
特别要指出的是,util.inspect 并不会简单地直接把对象转换为字符串,即使该对象定义了 toString 方法
也不会调用。
var util = require('util');
function Person() {
this.name = 'byvoid';
this.toString = function() {
return this.name;
};
}
var obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj, true));
//输出
// Person { name: 'byvoid', toString: [Function (anonymous)] }
// Person {
// name: 'byvoid',
// toString: [Function (anonymous)] {
// [length]: 0,
// [name]: '',
// [arguments]: null,
// [caller]: null,
// [prototype]: { [constructor]: [Circular *1] }
// }
// }
util.isArray(object),如果给定的参数 “object” 是一个数组返回 true,否则返回 false
var util = require('util');
util.isArray([])// true
util.isArray(new Array)// true
util.isArray({})// false
util.isRegExp(object),如果参数 “object” 是一个正则表达式返回true,否则返回false。
var util = require('util');
util.isRegExp(/some regexp/)// true
util.isRegExp(new RegExp('another regexp'))// true
util.isRegExp({}) // false
util.isDate(object),如果参数 “object” 是一个日期,返回true,否则返回false。
var util = require('util');
util.isDate(new Date()) // true
util.isDate(Date()) // false (without 'new' returns a String)
util.isDate({}) // false
node --inspect-brk xxx.js
chrome 浏览器输入网址:
chrome://inspect
检查当前被调试的程序
<script type="text/javascript">
function loadScript() {
console.log("current loadScript is");
let script = document.createElement("script");
script.type = "text/javascript";
script.src = "<%= BASE_URL %>env.js";
script.async=false;
document.head.appendChild(script);
}
console.log("current BASE_URL is"+"<%= BASE_URL %>");
// if("<%= BASE_URL %>"!==""){
// }
window.function(){
loadScript();
}
</script>