学习文档来源 nodejs中文网
fs - 文件系统
fs 模块提供了一些 API,用于以一种类似标准 POSIX 函数的方式与文件系统进行交互。
用法如下:
const fs = require('fs');
所有的文件系统操作都有异步和同步两种形式。
异步形式的最后一个参数都是完成时回调函数。 传给回调函数的参数取决于具体方法,但回调函数的第一个参数都会保留给异常。 如果操作成功完成,则第一个参数会是 null 或 undefined。
文件描述符
在 POSIX 系统,内核为所有进程维护着一张当前打开着的文件与资源的表格。 每个打开的文件都会分配一个名为文件描述符的数值标识。 在系统层,所有文件系统操作使用这些文件描述符来识别与追踪每个特定的文件。 Window 系统使用了一个不同但概念类似的机制来追踪资源。 为方便用户,Node.js 抽象了不同操作系统间的差异,为所有打开的文件分配了数值的文件描述符。fs.open() 方法用于分配一个新的文件描述符。 一旦分配了,文件描述符可用于读取数据、写入数据、或查看文件信息。
fs.open('/open/some/file.txt', 'r', (err, fd) => {
if (err) throw err;
fs.fstat(fd, (err, stat) => {
if (err) throw err;
// 各种操作
// 必须关闭文件描述符!
fs.close(fd, (err) => {
if (err) throw err;
});
});
});
fs.ReadStream 类
成功调用 fs.createReadStream() 会返回一个新的 fs.ReadStream 对象。fs.ReadStream 对象都是可读流。
fs.Stats 类
fs.Stats 对象提供了一个文件的信息。从 fs.stat()、fs.lstat() 和 fs.fstat() 及其同步版本返回的对象都是该类型。 如果传入这些函数的 options 中的 bigint 为 true,则数值会是 bigint 型而不是 number 型。
fs.WriteStream 类
WriteStream 是一个可写流。
fs.access(path[, mode], callback) //测试 path 指定的文件或目录的用户权限。 mode 参数是一个可选的整数,指定要执行的可访问性检查。 文件访问常量定义了 mode 可选的值。 可以创建由两个或更多个值的位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)
fs.appendFile(path, data[, options], callback) //异步地追加数据到一个文件,如果文件不存在则创建文件。 data 可以是一个字符串或 Buffer
fs.copyFile(src, dest[, flags], callback) //异步的将 src 拷贝到 dest
fs.createReadStream(path[, options])
fs.createWriteStream(path[, options])
//异步地创建目录。 完成回调只有一个可能的异常参数。 mode 默认为 0o777
fs.mkdir(path[, mode], callback)
fs.open(path, flags[, mode], callback) // 该回调有两个参数 (err, fd)
// 从 fd 指定的文件中读取数据。buffer 是数据将被写入到的 buffer。offset 是 buffer 中开始写入的偏移量。length 是一个整数,指定要读取的字节数。position 指定从文件中开始读取的位置。 如果 position 为 null,则数据从当前文件读取位置开始读取,且文件读取位置会被更新。 如果 position 为一个整数,则文件读取位置保持不变。
fs.read(fd, buffer, offset, length, position, callback)
// 读取一个目录的内容。 回调有两个参数 (err, files),其中 files 是目录中不包括 '.' 和 '..' 的文件名的数组
fs.readdir(path[, options], callback)
fs.readFile(path[, options], callback)
fs.rename(oldPath, newPath, callback)
fs.rmdir(path, callback)
// 异步地删除文件或符号链接。 除了可能的异常,完成回调没有其他参数,fs.unlink() 不能用于目录。 要删除目录,则使用 fs.rmdir()
fs.unlink(path, callback)
fs.stat(path[, options], callback)
fs.write(fd, buffer[, offset[, length[, position]]], callback)
fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])
global - 全局变量
Buffer 类
__dirname
__filename
clearImmediate(immediateObject)
clearInterval(intervalObject)
clearTimeout(timeoutObject)
console
exports
global
module
process
require()
setImmediate(callback[, ...args])
setInterval(callback, delay[, ...args])
setTimeout(callback, delay[, ...args])
http
要使用 HTTP 服务器与客户端,需要 require(‘http’)。
Node.js 中的 HTTP 接口被设计成支持协议的许多特性。 比如,大块编码的消息。 这些接口不缓冲完整的请求或响应,用户能够以流的形式处理数据。
http.request(options[, callback])
-
options Object | string | URL
protocol –string 使用的协议。默认为 http:。
host –string 请求发送至的服务器的域名或 IP 地址。默认为 localhost。hostname –string host 的别名。为了支持 url.parse(),hostname 优先于 host。
family –number 当解析 host 和 hostname 时使用的 IP 地址族。 有效值是 4 或 6。当未指定时,则同时使用 IP v4 和 v6。
port –number 远程服务器的端口。默认为 80。
localAddress –string 为网络连接绑定的本地接口。
socketPath –string Unix 域 Socket(使用 host:port 或 socketPath)。
method –string 指定 HTTP 请求方法的字符串。默认为 ‘GET’。
path –string 请求的路径。默认为 ‘/’。 应包括查询字符串(如有的话)。如 ‘/index.html?page=12’。 当请求的路径中包含非法字符时,会抛出异常。 目前只有空字符会被拒绝,但未来可能会变化。
headers –Object 包含请求头的对象。
auth –string 基本身份验证,如 ‘user:password’ 用来计算 Authorization 请求头。
agent –http.Agent | –boolean 控制 Agent 的行为。 可能的值有:undefined (默认): 对该主机和端口使用 http.globalAgent。 Agent 对象:显式地使用传入的 Agent。 false: 创建一个新的使用默认值的 Agent。 createConnection --Function 当不使用 agent 选项时,为请求创建一个 socket 或流。 这可以用于避免仅仅创建一个自定义的 Agent 类来覆盖默认的 createConnection 函数。详见agent.createConnection()。 Any Duplex stream is a valid return value. timeout --number : 指定 socket 超时的毫秒数。 它设置了 socket 等待连接的超时时间。
- callback –Function
- 返回: –http.ClientRequest
Node.js 为每台服务器维护多个连接来进行 HTTP 请求。 该函数允许显式地发出请求。
options 可以是一个对象、或字符串、或 URL 对象。 如果 options 是一个字符串,它会被自动使用 url.parse() 解析。 如果它是一个 URL 对象, 它会被默认转换成一个 options 对象。
可选的 callback 参数会作为单次监听器被添加到 ‘response’ 事件。
http.request() 返回一个 http.ClientRequest 类的实例。 ClientRequest 实例是一个 可写流。 如果需要通过 POST 请求上传一个文件,则写入到 ClientRequest 对象。
const postData = querystring.stringify({
'msg' : 'Hello World!'
});
const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应头: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`响应主体: ${chunk}`);
});
res.on('end', () => {
console.log('响应中已无数据。');
});
});
req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`);
});
// 写入数据到请求主体
req.write(postData);
req.end();
http.get(options[, callback])
- options –Object 或 string 或 URL 接收与http.request()相同的设置。 method一直设置为GET,忽略继承自原型的属性
- callback –Function 被调用时只传入一个参数,该参数是 http.IncomingMessage 的一个实例。
- 返回: http.ClientRequest
因为大多数请求都是 GET 请求且不带请求主体,所以 Node.js 提供了该便捷方法。 该方法与 http.request() 唯一的区别是它设置请求方法为 GET 且自动调用 req.end()。 注意,回调函数务必消耗掉响应数据,原因详见 http.ClientRequest 章节。
http.get('http://nodejs.org/dist/index.json', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('请求失败。\n' +
`状态码: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('无效的 content-type.\n' +
`期望 application/json 但获取的是 ${contentType}`);
}
if (error) {
console.error(error.message);
// 消耗响应数据以释放内存
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
// 客户端读取数据,可读流 IncomingMessage
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`错误: ${e.message}`);
});
http.createServer([options][, requestListener])
- option:
IncomingMessage (http.IncomingMessage) 指定要使用的 IncomingMessage 类,用于拓展原始的IncomingMessage类. 缺省: IncomingMessage.
ServerResponse (http.ServerResponse) 指定要使用的 ServerResponse类, 用于拓展原始的ServerResponse类. 缺省: ServerResponse. - requestListener (Function)
- 返回: (http.Server) 返回一个新的 http.Server实例。
requestListener是一个自动添加到’request’事件的方法。参数为 request (http.IncomingMessage) 和 response (http.ServerResponse)
类总结:
http.Agent 类 ————客户端管理请求的一些默认参数的agent类
http.ClientRequest ————客户端请求类,设置数据啥的等,实现的是可写流
http.Server 类 —————服务器端的server类,设置监听链接等,继承自 net.Server.
http.ServerResponse 类 —————服务器端的响应类,可写流
http.IncomingMessage 类 —————客户端的响应类 以及 服务器端的请求类,可读流
// 注意(attention):代码来源 https://github.com/chyingp/nodejs-learning-guide/blob/master/%E6%A8%A1%E5%9D%97/http.md
var http = require('http');
// http server 例子
var server = http.createServer(function(serverReq, serverRes){
var url = serverReq.url;
serverRes.end( '您访问的地址是:' + url );
});
server.listen(3000);
// http client 例子
var client = http.get('http://127.0.0.1:3000', function(clientRes){
clientRes.pipe(process.stdout);
});
// server:http.Server实例,用来提供服务,处理客户端的请求。
// client:http.ClientReques实例,用来向服务端发起请求。
// serverReq/clientRes:其实都是 http.IncomingMessage实。serverReq 用来获取客户端请求的相关信息,如request header;而clientRes用来获取服务端返回的相关信息,比如response header。
// serverRes:http.ServerResponse实例
http.Agent 类
Agent 负责为 HTTP 客户端管理连接的持续与复用。 它为一个给定的主机与端口维护着一个等待请求的队列,且为每个请求重复使用一个单一的 socket 连接直到队列为空,此时 socket 会被销毁或被放入一个连接池中,在连接池中等待被有着相同主机与端口的请求再次使用。 是否被销毁或被放入连接池取决于 keepAlive 选项。
new Agent([options])
options
- keepAlive –boolean 保持 socket 可用即使没有请求,以便它们可被将来的请求使用而无需重新建立一个 TCP 连接。默认为 false。
- keepAliveMsecs –number 当使用了 keepAlive 选项时,该选项指定 TCP Keep-Alive 数据包的 初始延迟。 当 keepAlive 选项为 false 或 undefined 时,该选项无效。 默认为 1000。
- maxSockets –number 每个主机允许的最大 socket 数量。 默认为 Infinity。
- maxFreeSockets –number 在空闲状态下允许打开的最大 socket 数量。 仅当 keepAlive 为 true 时才有效。 默认为 256。
http.request() 使用的默认 http.globalAgent 的选项均为各自的默认值。
若要配置其中任何一个,则需要创建自定义的 http.Agent 实例。
const http = require('http');
const keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
http.request(options, onResponseCallback);
http.ClientRequest 类
该对象在 http.request() 内部被创建并返回。 它表示着一个正在处理的请求,其请求头已进入队列。 请求头仍可使用 setHeader(name, value)、getHeader(name) 和 removeHeader(name) API 进行修改。 实际的请求头会与第一个数据块一起发送或当调用 request.end() 时发送。
要获取响应,需为 ‘response’ 事件添加一个监听器到请求对象上。 当响应头被接收到时,’response’ 事件会从请求对象上被触发 。 ‘response’ 事件被执行时带有一个参数,该参数是一个 http.IncomingMessage 实例。
该请求实现了 可写流 接口。 它是一个包含以下事件的 EventEmitter。
onst http = require('http');
const net = require('net');
const url = require('url');
// 创建一个 HTTP 代理服务器
const proxy = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, cltSocket, head) => {
// 连接到一个服务器
const srvUrl = url.parse(`http://${req.url}`);
const srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => {
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
srvSocket.write(head);
srvSocket.pipe(cltSocket);
cltSocket.pipe(srvSocket);
});
});
// 代理服务器正在运行
proxy.listen(1337, '127.0.0.1', () => {
// 发送一个请求到代理服务器
const options = {
port: 1337,
hostname: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
const req = http.request(options);
req.end();
req.on('connect', (res, socket, head) => {
console.log('已连接!');
// 通过代理服务器发送一个请求
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});
http.Server 类
该类继承自 net.Server.
const http = require('http');
const server = http.createServer((req, res) => {
res.end();
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
http.ServerResponse 类
该对象在 HTTP 服务器内部被创建。 它作为第二个参数被传入 ‘request’ 事件。
这个类实现了(而不是继承自)可写流 接口。
//此方法向服务器发出信号,表明已发送所有响应头和主体,该服务器应该视为此消息已完成。 必须在每个响应上调用此 response.end() 方法
response.end([data][, encoding][, callback])
response.getHeaders()
response.setHeader(name, value)
response.write(chunk[, encoding][, callback])
response.writeHead(statusCode[, statusMessage][, headers])
response.writeHead(statusCode[, statusMessage][, headers])
发送一个响应头给请求。 状态码是一个三位数的 HTTP 状态码,如 404。 最后一个参数 headers 是响应头。 第二个参数 statusMessage 是可选的状态描述。该方法在消息中只能被调用一次,且必须在 response.end() 被调用之前调用。如果在调用该方法之前调用 response.write() 或 response.end(),则隐式的响应头会被处理并调用该函数。 response.setHeader() 设置的响应头会与 response.writeHead() 设置的响应头合并,且 response.writeHead() 的优先。
// 返回 content-type = text/plain
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Foo', 'bar');
res.writeHead(200, 'ok', { 'Content-Type': 'text/plain' });
// 此方法向服务器发出信号,表明已发送所有响应头和主体,该服务器应该视为此消息已完成。 必须在每个响应上调用此 response.end() 方法
res.end('ok');
});
response.write(chunk[, encoding][, callback])
如果该方法被调用且 response.writeHead() 没有被调用,则它会切换到隐式响应头模式并刷新隐式响应头。
该方法会发送一块响应主体。 它可被多次调用,以便提供连续的响应主体片段。
请注意在http模块中,当请求是HEAD请求时,响应主体被省略。 类似地,204和304响应 不能 包括消息体。
chunk 可以是一个字符串或一个 buffer。 如果 chunk 是一个字符串,则第二个参数指定如何将它编码成一个字节流。 encoding 默认为 ‘utf8’。 当数据块被刷新时,callback 会被调用。
注意:这是原始的 HTTP 主体,且与可能被使用的高级主体编码无关。
response.write() 首次被调用时,会发送缓冲的响应头信息和响应主体的第一块数据到客户端。 response.write() 第二次被调用时,Node.js 能够确定数据会被接收,于是开始传输新数据。 也就是说,响应的完成取决于响应主体的第一块数据。
如果全部数据被成功刷新到内核缓冲区,则返回 true。 如果全部或部分数据还在内存中排队,则返回 false。 当缓冲区再次空闲时,则触发 ‘drain’ 事件。
http.IncomingMessage 类
IncomingMessage 对象由 http.Server 或 http.ClientRequest 创建,并作为第一个参数分别递给 ‘request’ 和 ‘response’ 事件。 它可以用来访问响应状态、消息头、以及数据。
它实现了 可读流 接口。
message.headers // 请求或响应的消息头对象
message.httpVersion
message.method // 仅对从 http.Server 获取的请求有效。
message.statusCode //3 位 HTTP 响应状态码。例如 404 仅对从 http.ClientRequest 获取的响应有效
message.statusMessage // 仅对从 http.ClientRequest 获取的响应有效
message.url // 请求的 URL 字符串。 它仅包含实际 HTTP 请求中存在的 URL, 仅对从 http.Server 获取的请求有效。
https
// curl -k https://localhost:8000/
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
module (模块)
在 Node.js 模块系统中,每个文件都被视为独立的模块。
总结#
想要获得调用 require() 时加载的确切的文件名,使用 require.resolve() 函数。 综上所述,以下用伪代码描述的高级算法,解释 require.resolve() 做了些什么:
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with '/'
a. set Y to be the filesystem root
3. If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. THROW "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.json is a file, parse X.json to a JavaScript Object. STOP
4. If X.node is a file, load X.node as binary addon. STOP
LOAD_INDEX(X)
1. If X/index.js is a file, load X/index.js as JavaScript text. STOP
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
3. If X/index.node is a file, load X/index.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. let M = X + (json main field)
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
从 node_modules 目录加载#
如果传递给 require() 的模块标识符不是一个核心模块,也没有以 ‘/’ 、 ‘../’ 或 ‘./’ 开头,则 Node.js 会从当前模块的父目录开始,尝试从它的 /node_modules 目录里加载模块。 Node.js 不会附加 node_modules 到一个已经以 node_modules 结尾的路径上。
如果还是没有找到,则移动到再上一层父目录,直到文件系统的根目录。
例子,如果在 ‘/home/ry/projects/foo.js’ 文件里调用了 require(‘bar.js’),则 Node.js 会按以下顺序查找:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
这使得程序本地化它们的依赖,避免它们产生冲突。
模块在第一次加载后会被缓存。 这也意味着(类似其他缓存机制)如果每次调用 require(‘foo’) 都解析到同一文件,则返回相同的对象。
多次调用 require(foo) 不会导致模块的代码被执行多次。 这是一个重要的特性。 借助它, 可以返回“部分完成”的对象,从而允许加载依赖的依赖, 即使它们会导致循环依赖。
模块包装器
(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});
module.exports 和 exports 快捷方式
module.exports 对象由 Module 系统创建。 有时这是不可接受的;许多人希望他们的模块成为某个类的实例。 为此,需要将期望导出的对象赋值给 module.exports。 注意,将期望的对象赋值给 exports 会简单地重新绑定本地的 exports 变量,这可能不是所期望的。exports 变量是在模块的文件级作用域内可用的,且在模块执行之前赋值给 module.exports。它允许使用快捷方式,因此 module.exports.f = … 可以更简洁地写成 exports.f = …。 但是,就像任何变量一样,如果为 exports 赋予了新值,则它将不再绑定到 module.exports。
path (路径)
path.basename(path[, ext]) //返回一个 path 的最后一部分
path.basename('/foo/bar/baz/asdf/quux.html'); // 返回: 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html'); // 返回: 'quux'
path.delimiter // 提供平台特定的路径分隔符:Windows 上是 ; POSIX 上是 :
path.dirname(path) // 返回一个 path 的目录名
path.extname // 返回 path 的扩展名
path.format(pathObject) // 从一个对象返回一个路径字符串
/* pathObject <Object>
dir <string>
root <string>
base <string>
name <string>
ext <string>
如果提供了 pathObject.dir,则 pathObject.root 会被忽略
如果提供了 pathObject.base 存在,则 pathObject.ext 和 pathObject.name 会被忽略
*/
path.parse(path) // 方法返回一个对象,对象的属性表示 path 的元素,与上面format正好相反
/*
path.parse('/home/user/dir/file.txt');
// 返回:
// { root: '/',
// dir: '/home/user/dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file' }
*/
path.join([...paths]) // 使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径,长度为零的 path 片段会被忽略。 如果连接后的路径字符串是一个长度为零的字符串,则返回 '.',表示当前工作目录。
/*
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
path.join('foo', {}, 'bar');
// 抛出 'TypeError: Path must be a string. Received {}'
*/
path.normalize(path) // 规范化给定的 path,并解析 '..' 和 '.' 片段
/*
path.normalize('/foo/bar//baz/asdf/quux/..');
// 返回: '/foo/bar/baz/asdf'
*/
path.relative(from, to) //从 from 到 to 的相对路径(基于当前工作目录)。 如果 from 和 to 各自解析到同一路径(调用 path.resolve()),则返回一个长度为零的字符串。 如果 from 或 to 传入了一个长度为零的字符串,则当前工作目录会被用于代替长度为零的字符串。
/*
path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb');
// 返回: '../../impl/bbb'
*/
path.resolve([...paths]) //把一个路径或路径片段的序列解析为一个 **绝对路径**。给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve('/foo', '/bar', 'baz') 会返回 /bar/baz。
//如果处理完全部给定的 path 片段后还未生成一个绝对路径,则当前工作目录会被用上。
//生成的路径是规范化后的,且末尾的斜杠会被删除,除非路径被解析为根目录。
//长度为零的 path 片段会被忽略。
//如果没有传入 path 片段,则 path.resolve() 会返回当前工作目录的绝对路径。
/*
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// 如果当前工作目录为 /home/myself/node,
// 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
*/
path.isAbsolute(path) // 判定 path 是否为一个绝对路径
path.sep //提供了平台特定的路径片段分隔符 Windows 上是 \ POSIX 上是 /
process - 进程
process 对象是一个全局变量,它提供当前 Node.js 进程的有关信息,以及控制当前 Node.js 进程。 因为是全局变量,所以无需使用 require()。
process 对象是 EventEmitter 的实例。
'exit' 事件 // 两种情况下 'exit' 事件会被触发:显式调用 process.exit() 方法,使得 Node.js 进程即将结束;Node.js 事件循环数组中不再有额外的工作,使得 Node.js 进程即将结束。'exit' 事件监听器的回调函数,只允许包含同步操作。
'message' 事件 // 如果 Node.js 进程是由 IPC 通道的方式创建的(详见子进程和集群文档),当子进程收到父进程发送的消息时(消息通过 childprocess.send() 发送),会触发 'message' 事件。
'rejectionHandled' 事件 // 如果有 Promise 被 rejected,并且此 Promise在 Node.js 事件循环的下次轮询及之后期间,被绑定了一个错误处理器(例如使用 promise.catch()),会触发 'rejectionHandled' 事件。
process.argv // process.argv 属性返回一个数组,这个数组包含了启动Node.js进程时的命令行参数。第一个元素为process.execPath。如果需要获取argv[0]的值请参见 process.argv0。第二个元素为当前执行的JavaScript文件路径。剩余的元素为其他命令行参数。
process.argv0 // 保存Node.js启动时传入的argv[0]参数值的一份只读副本
process.cwd() // 返回 Node.js 进程当前工作的目录
process.env // 返回一个包含用户环境信息的对象
process.execArgv // 返回当Node.js进程被启动时,Node.js特定的命令行选项。 这些选项在process.argv属性返回的数组中不会出现,并且这些选项中不会包括Node.js的可执行脚本名称或者任何在脚本名称后面出现的选项。 这些选项在创建子进程时是有用的,因为他们包含了与父进程一样的执行环境信息
process.execPath // 返回启动Node.js进程的可执行文件所在的绝对路径
process.nextTick(callback[, ...args]) // process.nextTick()方法将 callback 添加到"next tick 队列"。 一旦当前事件轮询队列的任务全部完成,在next tick队列中的所有callbacks会被依次调用。这种方式不是setTimeout(fn, 0)的别名。它更加有效率。事件轮询随后的ticks 调用,会在任何I/O事件(包括定时器)之前运行
process.platform // 返回字符串,标识Node.js进程运行其上的操作系统平台
process.send(message[, sendHandle[, options]][, callback]) // 如果Node.js进程是通过进程间通信产生的,那么,process.send()方法可以用来给父进程发送消息。 接收到的消息被视为父进程的ChildProcess对象上的一个'message'事件
process.version // 返回Node.js的版本信息
process.versions // 返回一个对象,此对象列出了Node.js和其依赖的版本信息
process.stdin // process.stdin 属性返回连接到 stdin (fd 0)的流。 它是一个net.Socket(它是一个Duplex流),除非 fd 0指向一个文件,在这种情况下它是一个Readable流。
process.stdout // process.stdout 属性返回连接到 stdout (fd 1)的流。 它是一个net.Socket (它是一个Duplex流), 除非 fd 1 指向一个文件,在这种情况下它是一个[可写][]流。
/*1:声明变量*/
var num1, num2;
/*2:向屏幕输出,提示信息,要求输入num1*/
process.stdout.write('请输入num1的值:');
/*3:监听用户的输入*/
process.stdin.on('data', function (chunk) {
if (!num1) {
num1 = Number(chunk);
/*4:向屏幕输出,提示信息,要求输入num2*/
process.stdout.write('请输入num2的值');
} else {
num2 = Number(chunk);
process.stdout.write('结果是:' + (num1 + num2));
}
});
string_decoder - 字符串解码器
string_decoder 模块提供了一个 API,用于把 Buffer 对象解码成字符串,但会保留编码过的多字节 UTF-8 与 UTF-16 字符。
当一个 Buffer 实例被写入 StringDecoder 实例时,会使用一个内部的 buffer 来确保解码后的字符串不会包含残缺的多字节字符。 残缺的多字节字符会被保存在这个 buffer 中,直到下次调用 stringDecoder.write() 或直到 stringDecoder.end() 被调用。
// 例子,欧元符号(€)的三个 UTF-8 编码的字节被分成三次操作写入:
const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');
decoder.write(Buffer.from([0xE2]));
decoder.write(Buffer.from([0x82]));
console.log(decoder.end(Buffer.from([0xAC])));
url
https:// | user: | pass@ | sub.host.com: | 8080 | /p/a/t/h | ?query=string | #hash |
---|---|---|---|---|---|---|---|
protocol | username | password | hostname | port | pathname | search | hash |
origin | origin | origin | pathname | search | hash |
url.format(URL[, options])#
const { URL } = require('url');
const myURL = new URL('https://a:b@你好你好?abc#foo');
console.log(myURL.href);
// 输出 https://a:b@xn--6qqa088eba/?abc#foo
console.log(myURL.toString());
// 输出 https://a:b@xn--6qqa088eba/?abc#foo
console.log(url.format(myURL, { fragment: false, unicode: true, auth: false }));
// 输出 'https://你好你好/?abc'
console.log(myURL.search);
// 输出 ?abc
myURL.search = 'abc=xyz';
console.log(myURL.href);
// 输出 https://a:b@xn--6qqa088eba/?abc=xyz#foo
Class: URL
url.hash // 获取及设置URL的分段(hash)部分
url.host // 获取及设置URL的主机(host--hostname+port)部分
url.hostname // 获取及设置URL的主机名(hostname)部分。 url.host和url.hostname之间的区别是url.hostname不 包含端口
url.href // 获取及设置序列化的URL,获取href属性的值等同于调用url.toString()。将此属性的值设置为新值等同于new URL(value)使用创建新的URL对象。URL对象的每个属性都将被修改。
url.origin // 获取只读序列化的URL origin部分
url.password // 获取及设置URL的密码(password)部分
url.pathname // 获取及设置URL的路径(path)部分
url.port // 获取及设置URL的端口(port)部分
url.protocol // 获取及设置URL的协议(protocol)部分
url.search // 获取及设置URL的序列化查询(query)部分部分
url.username // 获取及设置URL的用户名(username)部分
url.toString()
Class: URLSearchParams
URLSearchParamsAPI接口提供对URLquery部分的读写权限。URLSearchParams类也能够与以下四个构造函数中的任意一个单独使用。
WHATWG URLSearchParams接口和querystring模块有相似的目的,但是querystring模块的目的更加通用,因为它可以定制分隔符(&和=)。但另一方面,这个API是专门为URL查询字符串而设计的。
const { URL, URLSearchParams } = require('url');
const myURL = new URL('https://example.org/?abc=123');
console.log(myURL.searchParams.get('abc'));
// 输出 123
myURL.searchParams.append('abc', 'xyz');
console.log(myURL.href);
// 输出 https://example.org/?abc=123&abc=xyz
myURL.searchParams.delete('abc');
myURL.searchParams.set('a', 'b');
console.log(myURL.href);
// 输出 https://example.org/?a=b
const newSearchParams = new URLSearchParams(myURL.searchParams);
// 上面的代码等同于
// const newSearchParams = new URLSearchParams(myURL.search);
newSearchParams.append('a', 'c');
console.log(myURL.href);
// 输出 https://example.org/?a=b
console.log(newSearchParams.toString());
// 输出 a=b&a=c
// newSearchParams.toString() 被隐式调用
myURL.search = newSearchParams;
console.log(myURL.href);
// 输出 https://example.org/?a=b&a=c
newSearchParams.delete('a');
console.log(myURL.href);
// 输出 https://example.org/?a=b&a=c