nodejs api 中文文档
Node.js v0.10.18 手册 & 文档
目录
- 关于本文档
- 概述
- 全局对象
- 控制台
- 定时器
- Modules
- Addons插件
- process
- Exit Codes
- 事件: 'exit'
- 事件: 'uncaughtException'(未捕获错误)
- Signal Events
- process.stdout
- process.stderr
- process.stdin
- process.argv
- process.execPath
- process.execArgv
- process.abort()
- process.chdir(directory)
- process.cwd()
- process.env
- process.exit([code])
- process.exitCode
- process.getgid()
- process.setgid(id)
- process.getuid()
- process.setuid(id)
- process.getgroups()
- process.setgroups(groups)
- process.initgroups(user, extra_group)
- process.version
- process.versions
- process.config
- process.kill(pid, [signal])
- process.pid
- process.title
- process.arch
- process.platform
- process.memoryUsage()
- process.nextTick(callback)
- process.umask([mask])
- process.uptime()
- process.hrtime()
- utils
- Buffer
- 类: Buffer
- new Buffer(size)
- new Buffer(array)
- new Buffer(str, [encoding])
- 类方法: Buffer.isEncoding(encoding)
- 类方法: Buffer.isBuffer(obj)
- 类方法: Buffer.byteLength(string, [encoding])
- 类方法: Buffer.concat(list, [totalLength])
- buf.length
- buf.write(string, [offset], [length], [encoding])
- buf.toString([encoding], [start], [end])
- buf.toJSON()
- buf[index]
- buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])
- buf.slice([start], [end])
- buf.readUInt8(offset, [noAssert])
- buf.readUInt16LE(offset, [noAssert])
- buf.readUInt16BE(offset, [noAssert])
- buf.readUInt32LE(offset, [noAssert])
- buf.readUInt32BE(offset, [noAssert])
- buf.readInt8(offset, [noAssert])
- buf.readInt16LE(offset, [noAssert])
- buf.readInt16BE(offset, [noAssert])
- buf.readInt32LE(offset, [noAssert])
- buf.readInt32BE(offset, [noAssert])
- buf.readFloatLE(offset, [noAssert])
- buf.readFloatBE(offset, [noAssert])
- buf.readDoubleLE(offset, [noAssert])
- buf.readDoubleBE(offset, [noAssert])
- buf.writeUInt8(value, offset, [noAssert])
- buf.writeUInt16LE(value, offset, [noAssert])
- buf.writeUInt16BE(value, offset, [noAssert])
- buf.writeUInt32LE(value, offset, [noAssert])
- buf.writeUInt32BE(value, offset, [noAssert])
- buf.writeInt8(value, offset, [noAssert])
- buf.writeInt16LE(value, offset, [noAssert])
- buf.writeInt16BE(value, offset, [noAssert])
- buf.writeInt32LE(value, offset, [noAssert])
- buf.writeInt32BE(value, offset, [noAssert])
- buf.writeFloatLE(value, offset, [noAssert])
- buf.writeFloatBE(value, offset, [noAssert])
- buf.writeDoubleLE(value, offset, [noAssert])
- buf.writeDoubleBE(value, offset, [noAssert])
- buf.fill(value, [offset], [end])
- buffer.INSPECT_MAX_BYTES
- 类: SlowBuffer
- 类: Buffer
- 流
- 加密(Crypto)
- crypto.getCiphers()
- crypto.getHashes()
- crypto.createCredentials(details)
- crypto.createHash(algorithm)
- 类: Hash
- crypto.createHmac(algorithm, key)
- Class: Hmac
- crypto.createCipher(algorithm, password)
- crypto.createCipheriv(algorithm, key, iv)
- Class: Cipher
- crypto.createDecipher(algorithm, password)
- crypto.createDecipheriv(algorithm, key, iv)
- Class: Decipher
- crypto.createSign(algorithm)
- Class: Sign
- crypto.createVerify(algorithm)
- Class: Verify
- crypto.createDiffieHellman(prime_length)
- crypto.createDiffieHellman(prime, [encoding])
- Class: DiffieHellman
- diffieHellman.generateKeys([encoding])
- diffieHellman.computeSecret(other_public_key, [input_encoding], [output_encoding])
- diffieHellman.getPrime([encoding])
- diffieHellman.getGenerator([encoding])
- diffieHellman.getPublicKey([encoding])
- diffieHellman.getPrivateKey([encoding])
- diffieHellman.setPublicKey(public_key, [encoding])
- diffieHellman.setPrivateKey(private_key, [encoding])
- crypto.getDiffieHellman(group_name)
- crypto.pbkdf2(password, salt, iterations, keylen, callback)
- crypto.pbkdf2Sync(password, salt, iterations, keylen)
- crypto.randomBytes(size, [callback])
- crypto.pseudoRandomBytes(size, [callback])
- crypto.DEFAULT_ENCODING
- Recent API Changes
- TLS (SSL)
- Client-initiated renegotiation attack mitigation
- NPN 和 SNI
- tls.getCiphers()
- tls.createServer(options, [secureConnectionListener])
- tls.connect(options, [callback])
- tls.connect(port, [host], [options], [callback])
- 类: tls.TLSSocket
- new tls.TLSSocket(socket, options)
- tls.createSecurePair([credentials], [isServer], [requestCert], [rejectUnauthorized])
- 类: SecurePair
- 类: tls.Server
- 类: CryptoStream
- 类: tls.TLSSocket
- 字符串解码器
- File System
- fs.rename(oldPath, newPath, callback)
- fs.renameSync(oldPath, newPath)
- fs.ftruncate(fd, len, callback)
- fs.ftruncateSync(fd, len)
- fs.truncate(path, len, callback)
- fs.truncateSync(path, len)
- fs.chownSync(path, uid, gid)
- fs.fchown(fd, uid, gid, callback)
- fs.fchownSync(fd, uid, gid)
- fs.lchown(path, uid, gid, callback)
- fs.lchownSync(path, uid, gid)
- fs.chmod(path, mode, callback)
- fs.chmodSync(path, mode)
- fs.fchmod(fd, mode, callback)
- fs.fchmodSync(fd, mode)
- fs.lchmod(path, mode, callback)
- fs.lchmodSync(path, mode)
- fs.stat(path, callback)
- fs.lstat(path, callback)
- fs.fstat(fd, callback)
- fs.statSync(path)
- fs.lstatSync(path)
- fs.fstatSync(fd)
- fs.link(srcpath, dstpath, callback)
- fs.linkSync(srcpath, dstpath)
- fs.symlink(srcpath, dstpath, [type], callback)
- fs.symlinkSync(srcpath, dstpath, [type])
- fs.readlink(path, callback)
- fs.readlinkSync(path)
- fs.realpath(path, [cache], callback)
- fs.realpathSync(path, [cache])
- fs.unlink(path, callback)
- fs.unlinkSync(path)
- fs.rmdir(path, callback)
- fs.rmdirSync(path)
- fs.mkdir(path, [mode], callback)
- fs.mkdirSync(path, [mode])
- fs.readdir(path, callback)
- fs.readdirSync(path)
- fs.close(fd, callback)
- fs.closeSync(fd)
- fs.open(path, flags, [mode], callback)
- fs.openSync(path, flags, [mode])
- fs.utimes(path, atime, mtime, callback)
- fs.utimesSync(path, atime, mtime)
- fs.futimes(fd, atime, mtime, callback)
- fs.futimesSync(fd, atime, mtime)
- fs.fsync(fd, callback)
- fs.fsyncSync(fd)
- fs.write(fd, buffer, offset, length[, position], callback)
- fs.write(fd, data[, position[, encoding]], callback)
- fs.writeSync(fd, buffer, offset, length[, position])
- fs.writeSync(fd, data[, position[, encoding]])
- fs.read(fd, buffer, offset, length, position, callback)
- fs.readSync(fd, buffer, offset, length, position)
- fs.readFile(filename, [options], callback)
- fs.readFileSync(filename, [options])
- fs.writeFile(filename, data, [options], callback)
- fs.writeFileSync(filename, data, [options])
- fs.appendFile(filename, data, [options], callback)
- fs.appendFileSync(filename, data, [options])
- fs.watchFile(filename, [options], listener)
- fs.unwatchFile(filename, [listener])
- fs.watch(filename, [options], [listener])
- fs.exists(path, callback)
- fs.existsSync(path)
- Class: fs.Stats
- fs.createReadStream(path, [options])
- Class: fs.ReadStream
- fs.createWriteStream(path, [options])
- Class: fs.WriteStream
- Class: fs.FSWatcher
- 路径 (Path)
- net
- net.createServer([options], [connectionListener])
- net.connect(options, [connectionListener])
- net.createConnection(options, [connectionListener])
- net.connect(port, [host], [connectListener])
- net.createConnection(port, [host], [connectListener])
- net.connect(path, [connectListener])
- net.createConnection(path, [connectListener])
- 类: net.Server
- server.listen(port, [host], [backlog], [callback])
- server.listen(path, [callback])
- server.listen(handle, [callback])
- server.close([callback])
- server.address()
- server.unref()
- server.ref()
- server.maxConnections
- server.connections
- server.getConnections(callback)
- 事件: 'listening'
- 事件: 'connection'
- 事件: 'close'
- 事件: 'error'
- 类: net.Socket
- new net.Socket([options])
- socket.connect(port, [host], [connectListener])
- socket.connect(path, [connectListener])
- socket.bufferSize
- socket.setEncoding([encoding])
- socket.write(data, [encoding], [callback])
- socket.end([data], [encoding])
- socket.destroy()
- socket.pause()
- socket.resume()
- socket.setTimeout(timeout, [callback])
- socket.setNoDelay([noDelay])
- socket.setKeepAlive([enable], [initialDelay])
- socket.address()
- socket.unref()
- socket.ref()
- socket.remoteAddress
- socket.remotePort
- socket.localAddress
- socket.localPort
- socket.bytesRead
- socket.bytesWritten
- 事件: 'lookup'
- 事件: 'connect'
- 事件: 'data'
- 事件: 'end'
- 事件: 'timeout'
- 事件: 'drain'
- 事件: 'error'
- 事件: 'close'
- net.isIP(input)
- net.isIPv4(input)
- net.isIPv6(input)
- UDP / 数据报套接字
- dgram.createSocket(type, [callback])
- 类: dgram.Socket
- 事件: 'message'
- 事件: 'listening'
- 事件: 'close'
- 事件: 'error'
- socket.send(buf, offset, length, port, address, [callback])
- socket.bind(port, [address], [callback])
- socket.close()
- socket.address()
- socket.setBroadcast(flag)
- socket.setTTL(ttl)
- socket.setMulticastTTL(ttl)
- socket.setMulticastLoopback(flag)
- socket.addMembership(multicastAddress, [multicastInterface])
- socket.dropMembership(multicastAddress, [multicastInterface])
- socket.unref()
- socket.ref()
- DNS
- dns.lookup(domain, [family], callback)
- dns.resolve(domain, [rrtype], callback)
- dns.resolve4(domain, callback)
- dns.resolve6(domain, callback)
- dns.resolveMx(domain, callback)
- dns.resolveTxt(domain, callback)
- dns.resolveSrv(domain, callback)
- dns.resolveNs(domain, callback)
- dns.resolveCname(domain, callback)
- dns.reverse(ip, callback)
- dns.getServers()
- dns.setServers(servers)
- 错误代码
- HTTP
- http.STATUS_CODES
- http.createServer([requestListener])
- http.createClient([port], [host])
- Class: http.Server
- 事件 : 'request'
- 事件: 'connection'
- 事件: 'close'
- Event: 'checkContinue'
- 事件: 'connect'
- Event: 'upgrade'
- Event: 'clientError'
- server.listen(port, [hostname], [backlog], [callback])
- server.listen(path, [callback])
- server.listen(handle, [callback])
- server.close([callback])
- server.maxHeadersCount
- server.setTimeout(msecs, callback)
- server.timeout
- Class: http.ServerResponse
- 事件: 'close'
- response.writeContinue()
- response.writeHead(statusCode, [reasonPhrase], [headers])
- response.setTimeout(msecs, callback)
- response.statusCode
- response.setHeader(name, value)
- response.headersSent
- response.sendDate
- response.getHeader(name)
- response.removeHeader(name)
- response.write(chunk, [encoding])
- response.addTrailers(headers)
- response.end([data], [encoding])
- http.request(options, callback)
- http.get(options, callback)
- Class: http.Agent
- http.globalAgent
- Class: http.ClientRequest
- http.IncomingMessage
- HTTPS
- URL
- Query String
- punycode
- Readline
- REPL
- 执行 JavaScript
- 子进程
- 断言 (assert)
- assert.fail(actual, expected, message, operator)
- assert(value, message), assert.ok(value, [message])
- assert.equal(actual, expected, [message])
- assert.notEqual(actual, expected, [message])
- assert.deepEqual(actual, expected, [message])
- assert.notDeepEqual(actual, expected, [message])
- assert.strictEqual(actual, expected, [message])
- assert.notStrictEqual(actual, expected, [message])
- assert.throws(block, [error], [message])
- assert.doesNotThrow(block, [message])
- assert.ifError(value)
- TTY
- Zlib
- 例子
- zlib.createGzip([options])
- zlib.createGunzip([options])
- zlib.createDeflate([options])
- zlib.createInflate([options])
- zlib.createDeflateRaw([options])
- zlib.createInflateRaw([options])
- zlib.createUnzip([options])
- 类: zlib.Zlib
- 类: zlib.Gzip
- 类: zlib.Gunzip
- 类: zlib.Deflate
- 类: zlib.Inflate
- 类: zlib.DeflateRaw
- 类: zlib.InflateRaw
- 类: zlib.Unzip
- 快捷方法
- zlib.deflate(buf, [options], callback)
- zlib.deflateRaw(buf, [options], callback)
- zlib.Gzip(buf, [options], callback)
- zlib.gunzip(buf, [options], callback)
- zlib.inflate(buf, [options], callback)
- zlib.inflateRaw(buf, [options], callback)
- zlib.unzip(buf, [options], callback)
- 选项
- 内存使用调优
- 常量
- 操作系统
- 调试器
- 集群
- Smalloc
关于本文档#
本文档的目标是从参考和概念的角度全面解释 Node.js 的 API,每章节描述一个内置模块或高级概念。
在某些情况下,属性类型、方法参数以及事件处理过程(handler)参数 会被列在主标题下的列表中。
每一个 .html
文件都对应一份内容相同的结构化 .json
文档。这个特性现在还是实验性质的,希望能够为一些需要对文档进行操作的IDE或者其他工具提供帮助。
每个 .html
和 .json
文件都是基于源码的 doc/api/
目录下的 .markdown
文件生成的。本文档使用 tools/doc/generate.js
这个程序来生产的。 HTML 模板文件为 doc/template.html
。
稳定度#
在文档中,您可以了解每一个小节的稳定性。Node.js的API会有一些小的改变,当它成熟的时候,会有些部分相比另外一些来说更加可靠。有一部分接受过严格验证,被大量依赖的API几乎是不会改变的。也有一些是新增的、实验性的或者因被证实具有危险性而在重新设计中。
稳定度定义如下
稳定度: 5 - 已锁定
除非发现严重缺陷,该代码不会被更改。请不要对此区域提出更改,更改提议将被拒绝。
JSON 输出#
稳定度: 1 - 实验性
每个通过 markdown 生成的 HTML 文件都对应于一个具有相同数据的 JSON 文件。
该特性引入于 node v0.6.12。当前是测试性功能。
概述#
一个输出 “Hello World” 的简单 Web 服务器例子:
console.log('服务器已运行,请打开 http://127.0.0.1:8124/');
要运行这个服务器,先将程序保存为文件 “example.js”,并使用 node 命令来执行:
> node example.js
服务器已运行,请打开 http://127.0.0.1:8124/
所有的文档中的例子均使用相同的方式运行。
全局对象#
这些对象在所有模块中都是可用的。有些对象实际上并非在全局作用域内而是在模块作用域内——这种情况在以下文档中会特别指出。
global#
- {Object} 全局命名空间对象。
在浏览器中,顶级作用域就是全局作用域。这就是说,在浏览器中,如果当前是在全局作用域内,var something
将会声明一个全局变量。在Node中则不同。顶级作用域并非全局作用域,在Node模块里的var something
只属于那个模块。
process#
- {Object}
进程对象。见 进程对象章节。
console#
- {Object}
用于打印标准输出和标准错误。见控制台章节。
类: Buffer#
- {Function}
用于处理二进制数据。见Buffer章节。
require()#
- {Function}
引入模块。见Modules章节。require
实际上并非全局的而是各个模块本地的。
require.resolve()#
使用内部的require()
机制查找模块的位置,但不加载模块,只返回解析过的模块文件路径。
require.cache#
- {Object}
模块在引入时会缓存到该对象。通过删除该对象的键值,下次调用require
时会重新加载相应模块。
require.extensions#
稳定度:0 - 已废弃
- {Object}
指导require
方法如何处理特定的文件扩展名。
将.sjs
文件作为.js
文件处理:
require.extensions['.sjs'] = require.extensions['.js'];
已废弃 之前,该列表用于按需编译非JavaScript模块并加载进Node。然而,实践中有更好的方式实现该功能,如通过其他Node程序加载模块,或提前将他们编译成JavaScript代码。
由于模块系统的API已锁定,该功能可能永远不会去掉。改动它可能会产生细微的错误和复杂性,所以最好保持不变。
__filename#
- {String}
当前所执行代码文件的文件路径。这是该代码文件经过解析后的绝对路径。对于主程序来说,这和命令行中使用的文件路径未必是相同的。在模块中此变量值是该模块文件的路径。
例子:在/Users/mjr
下运行node example.js
console.log(__filename);
// /Users/mjr/example.js
__filename
实际上并非全局的而是各个模块本地的。
__dirname#
- {String}
当前执行脚本所在目录的目录名。
例子:在/Users/mjr
下运行node example.js
console.log(__dirname);
// /Users/mjr
__dirname
实际上并非全局的而是各个模块本地的。
module#
- {Object}
当前模块的引用。特别地,module.exports
和exports
指向同一个对象。module
实际上并非全局的而是各个模块本地的。
详情可见模块系统文档。
exports#
module.exports
对象的引用,该对象被当前模块的所有实例所共享,通过require()
可访问该对象。 何时使用exports
以及何时使用module.exports
的详情可参见模块系统文档。 exports
实际上并非全局的而是各个模块本地的。
详情可见模块系统文档。
关于模块系统的更多信息可参见模块 。
setTimeout(cb, ms)#
在至少ms
毫秒后调用回调cb
。实际延迟取决于外部因素,如操作系统定时器粒度及系统负载。
超时值必须在1-2147483647的范围内(包含1和2147483647)。如果该值超出范围,则该值被当作1毫秒处理。一般来说,一个定时器不能超过24.8天。
返回一个代表该定时器的句柄值。
clearTimeout(t)#
停止一个之前通过setTimeout()
创建的定时器。回调不会再被执行。
setInterval(cb, ms)#
每隔ms
毫秒重复调用回调cb
。注意,取决于外部因素,如操作系统定时器粒度及系统负载,实际间隔可能会改变。它不会少于ms
但可能比ms
长。
间隔值必须在1-2147483647的范围内(包含1和2147483647)。如果该值超出范围,则该值被当作1毫秒处理。一般来说,一个定时器不能超过24.8天。
返回一个代表该定时器的句柄值。
clearInterval(t)#
停止一个之前通过setInterval()
创建的定时器。回调不会再被执行。
定制器函数是全局变量。见定时器章节。
控制台#
稳定度: 4 - 冻结
- {Object}
用于向 stdout 和 stderr 打印字符。类似于大部分 Web 浏览器提供的 console 对象函数,在这里则是输出到 stdout 或 stderr。
当输出目标是一个终端或者文件时,console函数是同步的(为了防止过早退出时丢失信息).当输出目标是一个管道时它们是异步的(防止阻塞过长时间).
也就是说,在下面的例子中,stdout 是非阻塞的,而 stderr 则是阻塞的。
$ node script.js 2> error.log | tee info.log
在日常使用中,您不需要太担心阻塞/非阻塞的差别,除非您需要记录大量数据。
console.log([data], [...])#
向 stdout 打印并新起一行。这个函数可以像 printf()
那样接受多个参数,例如:
console.log('count: %d', count);
如果在第一个字符串中没有找到格式化元素,那么 util.inspect
将被应用到各个参数。详见 util.format()。
console.info([data], [...])#
同 console.log
。
console.error([data], [...])#
同 console.log
,但输出到 stderr。
console.warn([data], [...])#
同 console.error
。
console.dir(obj)#
对 obj
使用 util.inspect
并将结果字符串输出到 stdout。这个函数会忽略 obj
上的任何自定义 inspect()
。
console.time(label)#
标记一个时间点。
console.timeEnd(label)#
结束计时器,记录输出。例如:
console.time('100-elements');
for (var i = 0; i < 100; i++) {
;
}
console.timeEnd('100-elements');
console.trace(label)#
打印当前位置的栈跟踪到 stderr。
console.assert(expression, [message])#
与 assert.ok() 相同,如果 expression
执行结果为 false
则抛出一个带上 message
的 AssertionError。
定时器#
稳定度: 5 - 已锁定
所有的定时器函数都是全局变量. 你使用这些函数时不需要 require()
模块.
setTimeout(callback, delay, [arg], [...])#
调度 delay
毫秒后的一次 callback
执行。返回一个可能被 clearTimeout()
用到的 timeoutId
。可选地,您还能给回调传入参数。
请务必注意,您的回调有可能不会在准确的 delay
毫秒后被调用。Node.js 不保证回调被触发的精确时间和顺序。回调会在尽可能接近所指定时间上被调用。
clearTimeout(timeoutId)#
阻止一个 timeout 被触发。
setInterval(callback, delay, [arg], [...])#
调度每隔 delay
毫秒执行一次的 callback
。返回一个可能被 clearInterval()
用到的 intervalId
。可选地,您还能给回调传入参数。
clearInterval(intervalId)#
停止一个 interval 的触发。
unref()#
setTimeout
和 setInterval
所返回的值同时具有 timer.unref()
方法,允许您创建一个活动的、但当它是事件循环中仅剩的项目时不会保持程序运行的定时器。如果定时器已被 unref
,再次调用 unref
不会产生其它影响。
在 setTimeout
的情景中当您 unref
您会创建另一个定时器,并唤醒事件循环。创建太多这种定时器可能会影响事件循环的性能,慎用。
ref()#
如果您之前 unref()
了一个定时器,您可以调用 ref()
来明确要求定时器让程序保持运行。如果定时器已被 ref
那么再次调用 ref
不会产生其它影响。
setImmediate(callback, [arg], [...])#
调度在所有 I/O 事件回调之后、setTimeout
和 setInterval
之前“立即”执行 callback
。返回一个可能被 clearImmediate()
用到的 immediateId
。可选地,您还能给回调传入参数。
immediate 的回调以它们创建的顺序被加入队列。整个回调队列会在每个事件循环迭代中被处理。如果您在一个正被执行的回调中添加 immediate,那么这个 immediate 在下一个事件循环迭代之前都不会被触发。
clearImmediate(immediateId)#
停止一个 immediate 的触发。
Modules#
稳定度: 5 - 已锁定
Node有一个简易的模块加载系统。在node中,文件和模块是一一对应的。下面示例是foo.js
加载同一目录下的circle.js
。
foo.js
的内容:
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
circle.js
的内容:
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
circle.js
模块输出了area()
和circumference()
两个函数。要输出某个对象,把它加到exports
这个特殊对象下即可。
注意,exports
是module.exports
的一个引用,只是为了用起来方便。当你想输出的是例如构造函数这样的单个项目,那么需要使用module.exports
。
// 正确输出构造函数
module.exports = MyConstructor;
模块内的本地变量是私有的。在这里例子中,PI
这个变量就是circle.js
私有的。
模块系统的实现在require("module")
中。
循环#
当存在循环的require()
调用时,一个模块可能在返回时并不会被执行。
考虑这样一种情形:
a.js
:
console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js
:
console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js
:
console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
首先main.js
加载a.js
,接着a.js
又去加载b.js
。这时,b.js
会尝试去加载a.js
。为了防止无限的循环,a.js
会返回一个unfinished copy给b.js
。然后b.js
就会停止加载,并将其exports
对象返回给a.js
模块。
这样main.js
就把这两个模块都加载完成了。这段程序的输出如下:
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
如果你的程序中有循环的模块依赖,请确保工作正常。
核心模块#
Node中有一些模块是编译成二进制的。这些模块在本文档的其他地方有更详细的描述。
核心模块定义在node源代码的lib/
目录下。
require()
总是会优先加载核心模块。例如,require('http')
总是返回编译好的HTTP模块,而不管是否有这个名字的文件。
文件模块#
如果按文件名没有查找到,那么node会添加 .js
和 .json
后缀名,再尝试加载,如果还是没有找到,最后会加上.node
的后缀名再次尝试加载。
.js
会被解析为Javascript纯文本文件,.json
会被解析为JSON格式的纯文本文件. .node
则会被解析为编译后的插件模块,由dlopen
进行加载。
模块以'/'
为前缀,则表示绝对路径。例如,require('/home/marco/foo.js')
,加载的是/home/marco/foo.js
这个文件。
模块以'./'
为前缀,则路径是相对于调用require()
的文件。 也就是说,circle.js
必须和foo.js
在同一目录下,require('./circle')
才能找到。
当没有以'/'或者'./'来指向一个文件时,这个模块要么是"核心模块",要么就是从node_modules
文件夹加载的。
如果指定的路径不存在,require()
会抛出一个code
属性为'MODULE_NOT_FOUND'
的错误。
从node_modules
文件夹中加载#
如果require()
中的模块名不是一个本地模块,也没有以'/'
, '../'
, 或是 './'
开头,那么node会从当前模块的父目录开始,尝试在它的/node_modules
文件夹里加载相应模块。
如果没有找到,那么就再向上移动到父目录,直到到达顶层目录位置。
例如,如果位于'/home/ry/projects/foo.js'
的文件调用了require('bar.js')
,那么node查找的位置依次为:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
这就要求程序员应尽量把依赖放在就近的位置,以防崩溃。
Folders as Modules#
可以把程序和库放到一个单独的文件夹里,并提供单一入口来指向它。有三种方法,使一个文件夹可以作为require()
的参数来加载。
首先是在文件夹的根目录创建一个叫做package.json
的文件,它需要指定一个main
模块。下面是一个package.json文件的示例。
{ "name" : "some-library",
"main" : "./lib/some-library.js" }
示例中这个文件,如果是放在./some-library
目录下面,那么require('./some-library')
就将会去加载./some-library/lib/some-library.js
。
This is the extent of Node's awareness of package.json files.
如果目录里没有package.json这个文件,那么node就会尝试去加载这个路径下的index.js
或者index.node
。例如,若上面例子中,没有package.json,那么require('./some-library')
就将尝试加载下面的文件:
./some-library/index.js
./some-library/index.node
Caching#
模块在第一次加载后会被缓存。这意味着(类似其他缓存)每次调用require('foo')
的时候都会返回同一个对象,当然,必须是每次都解析到同一个文件。
Multiple calls to require('foo')
may not cause the module code to be executed multiple times. This is an important feature. With it, "partially done" objects can be returned, thus allowing transitive dependencies to be loaded even when they would cause cycles.
如果你希望一个模块多次执行,那么就输出一个函数,然后调用这个函数。
Module Caching Caveats#
模块的缓存是依赖于解析后的文件名。由于随着调用的位置不同,可能解析到不同的文件(比如需从node_modules
文件夹加载的情况),所以,如果解析到其他文件时,就不能保证require('foo')
总是会返回确切的同一对象。
The module
Object#
- {Object}
在每一个模块中,变量 module
是一个代表当前模块的对象的引用。 特别地,module.exports
可以通过全局模块对象 exports
获取到。 module
不是事实上的全局对象,而更像是每个模块内部的。
module.exports#
- {Object}
module.exports
对象是通过模块系统产生的。有时候这是难以接受的,许多人想让他们的模块是某个类的实例。 因此,将要导出的对象赋值给 module.exports
。例如,假设我们有一个模块称之为 a.js
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
module.exports.emit('ready');
}, 1000);
那么,在另一个文件中我们可以这样写
var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});
Note that assignment to module.exports
must be done immediately. It cannot be done in any callbacks. This does not work:
x.js:
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
y.js:
var x = require('./x');
console.log(x.a);
module.require(id)#
id
{String}- Return: {Object} 已解析模块的
module.exports
module.require
方法提供了一种像 require()
一样从最初的模块加载一个模块的方法。
注意,为了这样做,你必须取得一个对 module
对象的引用。 require()
返回 module.exports
,并且 module
是一个典型的只能在特定模块作用域内有效的变量,如果要使用它,就必须明确的导出。
module.id#
- {String}
用于区别模块的标识符。通常是完全解析后的文件名。
module.filename#
- {String}
模块完全解析后的文件名。
module.loaded#
- {Boolean}
不论该模块是否加载完毕,或者正在加载的过程中。
module.parent#
- {Module Object}
引入这个模块的模块。
module.children#
- {Array}
这个模块引入的所有模块对象。
总体来说...#
为了获取调用 require
加载的确切的文件名,使用 require.resolve()
函数。
综上所述,下面用伪代码的高级算法形式表达了 require.resolve 是如何工作的:
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
a. if PARTS[I] = "node_modules" CONTINUE
c. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIR
c. let I = I - 1
6. return DIRS
从全局文件夹加载#
如果 NODE_PATH
环境变量设置为一个以冒号分割的绝对路径的列表, 找不到模块时 node 将会从这些路径中搜索模块。 (注意:在 windows 操作系统上,NODE_PATH
是以分号间隔的)
此外,node 将会搜索以下地址:
- 1:
$HOME/.node_modules
- 2:
$HOME/.node_libraries
- 3:
$PREFIX/lib/node
$HOME
是用户的主目录,$PREFIX
是 node 里配置的 node_prefix
。
这些大多是由于历史原因。强烈建议读者将所依赖的模块放到 node_modules
文件夹里。 这样加载的更快也更可靠。
访问主模块#
当 Node 直接运行一个文件时,require.main
就被设置为它的 module
。 也就是说你可以判断一个文件是否是直接被运行的
require.main === module
对于一个 foo.js
文件,如果通过 node foo.js
运行是 true
,但是通过 require('./foo')
运行却是 false
。
因为 module
提供了一个 filename
属性(通常等于 __filename
), 所以当前程序的入口点可以通过 require.main.filename
来获取。
附录: 包管理技巧#
Node 的 require()
函数的语义被设计的足够通用化,以支持各种常规目录结构。 包管理程序如 dpkg,rpm 和 npm 将不用修改就能够从 Node 模块构建本地包。
接下来我们将给你一个可行的目录结构建议:
假设我们希望将一个包的指定版本放在 /usr/lib/node/<some-package>/<some-version>
目录中。
包可以依赖于其他包。为了安装包 foo,可能需要安装包 bar 的一个指定版本。 包 bar 也可能有依赖关系,在某些情况下依赖关系可能发生冲突或者形成循环。
因为 Node 会查找它所加载的模块的真实路径(也就是说会解析符号链接), 然后按照上文描述的方式在 node_modules 目录中寻找依赖关系,这种情形跟以下体系结构非常相像:
- /usr/lib/node/foo/1.2.3/ - foo 包 1.2.3 版本的内容
- /usr/lib/node/bar/4.3.2/ - foo 包所依赖的 bar 包的内容
- /usr/lib/node/foo/1.2.3/node_modules/bar - 指向 /usr/lib/node/bar/4.3.2/ 的符号链接
- /usr/lib/node/bar/4.3.2/node_modules/* - 指向 bar 包所依赖的包的符号链接
因此即便存在循环依赖或依赖冲突,每个模块还是可以获得他所依赖的包的一个可用版本。
当 foo 包中的代码调用 require('bar'),将获得符号链接 /usr/lib/node/foo/1.2.3/node_modules/bar
指向的版本。 然后,当 bar 包中的代码调用 require('queue')
,将会获得符号链接 /usr/lib/node/bar/4.3.2/node_modules/quux
指向的版本。
此外,为了进一步优化模块搜索过程,不要将包直接放在 /usr/lib/node
目录中,而是将它们放在 /usr/lib/node_modules/<name>/<version>
目录中。 这样在依赖的包找不到的情况下,就不会一直寻找 /usr/node_modules
目录或 /node_modules
目录了。
为了使模块在 node 的 REPL 中可用,你可能需要将 /usr/lib/node_modules
目录加入到 $NODE_PATH
环境变量中。 由于在 node_modules 目录中搜索模块使用的是相对路径,基于调用 require()
的文件所在真实路径,因此包本身可以放在任何位置。
Addons插件#
Addons插件就是动态连接库。它类似胶水,将c、c++和Node粘贴起来。它的API(目前来说)相当复杂,涉及到了几个类库的知识。
- V8 JavaScript引擎,一个 C++ 类库. 用于和JavaScript进行交互的接口。 创建对象, 调用函数等. 文档大部分在这里:
v8.h
头文件 (deps/v8/include/v8.h
在Node源代码目录里), 也有可用的线上文档 线上. (译者:想要学习c++的addons插件编写,必须先了解v8的接口)
- libuv, C语言编写的事件循环类库。任何时候需要等待一个文件描述符变为可读状态,等待一个定时器,或者等待一个接受信号都需要使用libuv类库的接口。也就是说,如果你执行任何I/O操作,libuv类库将会被用到。
- 内部 Node 类库.最重要的接口就是
node::ObjectWrap
类,这个类你应该是最可能想要派生的。
- 其他.请参阅
deps/
获得更多可用类库。
Node 静态编译了所有依赖到它的可执行文件中去了。当编译你的模块时,你不必担心无法连接上述那些类库。 (译者:换而言之,你在编译自己的addons插件时,只管在头部 #include <uv.h>,不必在binding.gyp中声明)
下面所有的例子都可以下载到: 下载 这或许能成为你学习和创作自己addon插件的起点。
Hello world(世界你好)#
作为开始,让我们用编写一个小的addon插件,这个addon插件的c++代码相当于下面的JavaScript代码。
module.exports.hello = function() { return 'world'; };
首先我们创建一个 hello.cc
文件:
NODE_MODULE(hello, init)//译者:将addon插件名hello和上述init函数关联输出
注意所有Node的addons插件都必须输出一个初始化函数:
void Initialize (Handle<Object> exports);
NODE_MODULE(module_name, Initialize)
在NODE_MODULE
之后没有分号,因为它不是一个函数(请参阅node.h
)
这个module_name
(模块名)需要和最后编译生成的2进制文件名(减去.node后缀名)相同。
源代码需要生成在hello.node
,这个2进制addon插件中。 需要做到这些,我们要创建一个名为binding.gyp
的文件,它描述了创建这个模块的配置,并且它的格式是类似JSON的。 文件将被命令:node-gyp 编译。
{
"targets": [
{
"target_name": "hello", //译者:addon插件名,注意这里的名字必需和上面NODE_MODULE中的一致
"sources": [ "hello.cc" ] //译者:这是需要编译的源文件
}
]
}
下一步是根据当前的操作系统平台,利用node-gyp configure
命令,生成合适的项目文件。
现在你会有一个Makefile
(在Unix平台) 或者一个 vcxproj
file (在Windows上),它们都在build/
文件夹中. 然后执行命令 node-gyp build
进行编译。 (译者:当然你可以执行 node-gyp rebuild
一步搞定)
现在你已经有了编译好的 .node
文件了,这个编译好的绑定文件会在目录 build/Release/
下
现在你可以使用这个2进制addon插件在Node项目hello.js
中了,通过指明require
这个刚刚创建的hello.node
模块使用它。
console.log(addon.hello()); // 'world'
请阅读下面的内容获得更多详情或者访问https://github.com/arturadib/node-qt获取一个生产环境的例子。
Addon patterns(插件方式)#
下面是一些帮助你开始编写addon插件的方式。参考这个在线的v8 手册用来帮助你调用各种v8接口, 然后是v8的 嵌入式开发向导 ,解释几个概念,如 handles, scopes,function templates等。
为了能跑起来这些例子,你必须用 node-gyp
来编译他们。 创建一个binding.gyp
文件:
{
"targets": [
{
"target_name": "addon",
"sources": [ "addon.cc" ]
}
]
}
事实上可以有多个 .cc
文件, 就简单的在 sources
数组里加上即可,例子:
"sources": ["addon.cc", "myexample.cc"]
现在你有了你的binding.gyp
文件了,你可要开始执行configure 和 build 命令构建你的addon插件了
$ node-gyp configure build
Function arguments(函数参数)#
下面的部分说明了如何从JavaScript的函数调用获得参数然后返回一个值。这是主要的内容并且仅需要源代码addon.cc
。
NODE_MODULE(addon, Init)
你可以使用下面的JavaScript代码片段来测试它
console.log( 'This should be eight:', addon.add(3,5) );
Callbacks(回调)#
你可以传递JavaScript functions 到一个C++ function 并且执行他们,这里是 addon.cc
文件:
NODE_MODULE(addon, Init)
注意这个例子对Init()
使用了两个参数,将完整的 module
对象作为第二个参数传入。这允许addon插件完全的重写 exports
,这样就可以用一个函数代替多个函数作为exports
的属性了。
你可以使用下面的JavaScript代码片段来测试它
addon(function(msg){
console.log(msg); // 'hello world'
});
Object factory(对象工厂)#
在这个addon.cc
文件里用一个c++函数,你可以创建并且返回一个新的对象,这个新的对象拥有一个msg的属性,它的值是通过createObject()方法传入的
NODE_MODULE(addon, Init)
在js中测试如下:
var obj1 = addon('hello');
var obj2 = addon('world');
console.log(obj1.msg+' '+obj2.msg); // 'hello world'
Function factory(函数工厂)#
这次将展示如何创建并返回一个JavaScript function函数,这个函数其实是通过c++包装的。
NODE_MODULE(addon, Init)
测试它:
var fn = addon();
console.log(fn()); // 'hello world'
Wrapping C++ objects(包装c++对象)#
这里将创建一个被c++包裹的对象或类MyObject
,它是可以在JavaScript中通过new
操作符实例化的。 首先我们要准备主要的模块文件addon.cc
:
NODE_MODULE(addon, InitAll)
然后在myobject.h
文件中创建你的包装类,它继承自 node::ObjectWrap
:
#endif
在文件 myobject.cc
可以实施各种你想要暴露给js的方法。 这里我们暴露方法名为 plusOne
给就是,它表示将构造函数的属性加1.
return scope.Close(Number::New(obj->counter_));
}
测试它:
var obj = new addon.MyObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13
Factory of wrapped objects(工厂包装对象)#
这是非常有用的,当你想创建原生的JavaScript对象时,又不想明确的使用JavaScript的new
操作符。
var obj = addon.createObject();
// 用上面的方式代替下面的:
// var obj = new addon.Object();
让我们注册在 addon.cc
文件中注册createObject
方法:
NODE_MODULE(addon, InitAll)
在myobject.h
文件中,我们现在介绍静态方法NewInstance,它能够实例化对象(举个例子,它的工作就像是 在JavaScript中的
new` 操作符。)
#endif
这里的处理方式和上面的 myobject.cc
很像:
return scope.Close(Number::New(obj->counter_));
}
测试它:
var obj2 = createObject(20);
console.log( obj2.plusOne() ); // 21
console.log( obj2.plusOne() ); // 22
console.log( obj2.plusOne() ); // 23
Passing wrapped objects around(传递包装的对象)#
除了包装和返回c++对象以外,你可以传递他们并且通过Node的node::ObjectWrap::Unwrap
帮助函数解包装他们。 在下面的addon.cc
文件中,我们介绍了一个函数add()
,它能够获取2个MyObject
对象。
NODE_MODULE(addon, InitAll)
为了使事情变得有趣,我们在 myobject.h
采用一个公共的方法,所以我们能够在unwrapping解包装对象之后使用私有成员的值。
#endif
myobject.cc
文件的处理方式和前面类似
return scope.Close(instance);
}
测试它:
var obj1 = addon.createObject(10);
var obj2 = addon.createObject(20);
var result = addon.add(obj1, obj2);
console.log(result); // 30
process#
process
对象是一个全局对象,可以在任何地方访问到它。 它是EventEmitter的一个实例。
Exit Codes#
Node 执行程序正常情况下会返回 0,这也意味着,包括所有“异步”在内的操作都已结束。(笔者注:linux terminal 下使用 echo $? 查看,win cmd 下使用 echo %ERRORLEVEL% 查看)除此之外的其他返回状态如下:
1
未捕获的致命异常(Uncaught Fatal Exception) - There was an uncaught exception, and it was not handled by a domain or anuncaughtException
event handler.2
- 未使用(Unused) (reserved by Bash for builtin misuse)3
解析错误(Internal JavaScript Parse Error) - The JavaScript source code internal in Node's bootstrapping process caused a parse error. This is extremely rare, and generally can only happen during development of Node itself.4
评估失败(Internal JavaScript Evaluation Failure) - The JavaScript source code internal in Node's bootstrapping process failed to return a function value when evaluated. This is extremely rare, and generally can only happen during development of Node itself.5
致命错误(Fatal Error) - There was a fatal unrecoverable error in V8. Typically a message will be printed to stderr with the prefixFATAL ERROR
.6
未正确的异常处理(Non-function Internal Exception Handler) - There was an uncaught exception, but the internal fatal exception handler function was somehow set to a non-function, and could not be called.7
异常处理函数运行时失败(Internal Exception Handler Run-Time Failure) - There was an uncaught exception, and the internal fatal exception handler function itself threw an error while attempting to handle it. This can happen, for example, if aprocess.on('uncaughtException')
ordomain.on('error')
handler throws an error.8
- 未使用(Unused). In previous versions of Node, exit code 8 sometimes indicated an uncaught exception.9
- 无效的参数(Invalid Argument) - Either an unknown option was specified, or an option requiring a value was provided without a value.10
运行时失败(Internal JavaScript Run-Time Failure) - The JavaScript source code internal in Node's bootstrapping process threw an error when the bootstrapping function was called. This is extremely rare, and generally can only happen during development of Node itself.12
无效的调试参数(Invalid Debug Argument) - The--debug
and/or--debug-brk
options were set, but an invalid port number was chosen.>128
信号退出(Signal Exits) - If Node receives a fatal signal such asSIGKILL
orSIGHUP
, then its exit code will be128
plus the value of the signal code. This is a standard Unix practice, since exit codes are defined to be 7-bit integers, and signal exits set the high-order bit, and then contain the value of the signal code.
事件: 'exit'#
当进程将要退出时触发。这是一个在固定时间检查模块状态(如单元测试)的好时机。需要注意的是 'exit' 的回调结束后,主事件循环将不再运行,所以计时器也会失效。
监听 exit
事件的例子:
process.on('exit', function() {
// 设置一个延迟执行
setTimeout(function() {
console.log('主事件循环已停止,所以不会执行');
}, 0);
console.log('退出前执行');
});
事件: 'uncaughtException'(未捕获错误)#
当一个异常冒泡回归到事件循环中就会触发这个事件,如果建立了一个监听器来监听这个异常,默认的行为(打印堆栈跟踪信息并退出)就不会发生。
监听 uncaughtException
示例:
// 故意制造一个异常,而且不catch捕获它.
nonexistentFunc();
console.log('This will not run.');
注意,uncaughtException
未捕获异常是一个非常粗略的异常处理。
尽量不要使用它,使用 domains 来代替它,如果你已经使用了,请在不处理这个异常之后重启你的应用。
请 不要 象使用node.js的有错误回复执行
这样使用.一个未处理异常意味着你的应用和你的扩展Node.js自身是有未知状态的。盲目的恢复意味着任何事情都可能发生。
你在升级的系统时拉掉了电源线,然后恢复了。可能10次里有9次每一偶问题,但是第10次,你的系统就会崩溃。
你已经被警告。
Signal Events#
当进程接收到信号时触发。信号列表详见 POSIX 标准的 sigaction(2)如 SIGINT、SIGUSR1 等。
监听 SIGINT
信号的示例:
// 设置 'SIGINT' 信号触发事件
process.on('SIGINT', function() {
console.log('收到 SIGINT 信号。 退出请使用 Ctrl + D ');
});
在大多数终端下,一个发送 SIGINT
信号的简单方法是按下 ctrl + c
。
process.stdout#
一个指向标准输出流(stdout)
的 可写的流(Writable Stream)
。
举例: console.log
的实现
console.log = function(d) {
process.stdout.write(d + '\n');
};
process.stderr 和 process.stdout 不像 Node 中其他的流(Streams) 那样,他们通常是阻塞式的写入。当其引用指向 普通文件
或者 TTY文件描述符
时他们就是阻塞的(注:TTY 可以理解为终端的一种,可联想 PuTTY,详见百科)。当他们引用指向管道(pipes)时,他们就同其他的流(Streams)一样是非阻塞的。
要检查 Node 是否正在运行一个 TTY上下文 中(注:linux 中没有运行在 tty 下的进程是 守护进程
),可以用使用 process.stderr、process.stdout 或 process.stdin 的 isTTY 属性:
$ node -p "Boolean(process.stdout.isTTY)"
true
$ node -p "Boolean(process.stdout.isTTY)" | cat
false
更多信息,请查看 tty 文档。
process.stderr#
一个指向标准错误流(stderr)的 可写的流(Writable Stream)。
process.stderr 和 process.stdout 不像 Node 中其他的流(Streams) 那样,他们通常是阻塞式的写入。当其引用指向 普通文件
或者 TTY文件描述符
时他们就是阻塞的(注:TTY 可以理解为终端的一种,可联想 PuTTY,详见百科)。当他们引用指向管道(pipes)时,他们就同其他的流(Streams)一样是非阻塞的。
process.stdin#
一个指向 标准输入流(stdin) 的可读流(Readable Stream)。标准输入流默认是暂停 (pause) 的,所以必须要调用 process.stdin.resume() 来恢复 (resume) 接收。
打开标准输入流,并监听两个事件的示例:
process.stdin.on('end', function() {
process.stdout.write('end');
});
// gets 函数的简单实现
function gets(cb){
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(chunk) {
process.stdin.pause();
cb(chunk);
});
}
gets(function(reuslt){
console.log("["+reuslt+"]");
});
process.argv#
一个包含命令行参数的数组。第一个元素会是 'node', 第二个元素将是 .Js 文件的名称。接下来的元素依次是命令行传入的参数。
// 打印 process.argv
process.argv.forEach(function(val, index, array) {
console.log(index + ': ' + val);
});
输出将会是:
$ node process-2.js one two=three four
0: node
1: /Users/mjr/work/node/process-2.js
2: one
3: two=three
4: four
process.execPath#
开启当前进程的这个可执行文件的绝对路径。
示例:
/usr/local/bin/node
process.execArgv#
与 process.argv
类似,不过是用于保存 node特殊(node-specific) 的命令行选项(参数)。这些特殊的选项不会出现在 process.argv
中,而且 process.execArgv 不会保存 process.argv
中保存的参数(如 0:node 1:文件名 2.3.4.参数 等), 所有文件名之后的参数都会被忽视。这些选项可以用于派生与与父进程相同执行环境的子进程。
示例:
$ node --harmony script.js --version
process.execArgv 中的特殊选项:
['--harmony']
process.argv 接收到的参数:
['/usr/local/bin/node', 'script.js', '--version']
process.abort()#
这将导致 Node 触发一个abort事件,这会导致Node退出并且创建一个核心文件。
process.chdir(directory)#
改变进程的当前进程的工作目录,若操作失败则抛出异常。
console.log('当前目录:' + process.cwd());
try {
process.chdir('/tmp');
console.log('新目录:' + process.cwd());
}
catch (err) {
console.log('chdir: ' + err);
}
process.cwd()#
返回进程当前的工作目录。
console.log('当前目录:' + process.cwd());
process.env#
一个包括用户环境的对象。详细参见 environ(7)。
process.exit([code])#
终止当前进程并返回给定的 code
。如果省略了 code
,退出是会默认返回成功的状态码('success' code) 也就是 0
。
退出并返回失败的状态 ('failure' code):
process.exit(1);
执行上述代码,用来执行 node 的 shell 就能收到值为 1 的 exit code
process.exitCode#
当进程既正常退出,或者通过未指定 code 的 process.exit()
退出时,这个属性中所存储的数字将会成为进程退出的错误码 (exit code)。
如果指名了 process.exit(code)
中退出的错误码 (code),则会覆盖掉 process.exitCode
的设置。
process.getgid()#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
获取进程的群组标识(详见getgid(2))。获取到的是群组的数字ID,不是群组名称。
if (process.getgid) {
console.log('当前 gid: ' + process.getgid());
}
process.setgid(id)#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
设置进程的群组标识(详见getgid(2))。参数可以是一个数字ID或者群组名字符串。如果指定了一个群组名,这个方法会阻塞等待将群组名解析为数字ID。
if (process.getgid && process.setgid) {
console.log('当前 gid: ' + process.getgid());
try {
process.setgid(501);
console.log('新 gid: ' + process.getgid());
}
catch (err) {
console.log('设置 gid 失败: ' + err);
}
}
process.getuid()#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
获取执行进程的用户ID(详见getgid(2))。这是用户的数字ID,不是用户名。
if (process.getuid) {
console.log('当前 uid: ' + process.getuid());
}
process.setuid(id)#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
设置执行进程的用户ID(详见getgid(2))。参数可以使一个数字ID或者用户名字符串。如果指定了一个用户名,那么该方法会阻塞等待将用户名解析为数字ID。
if (process.getuid && process.setuid) {
console.log('当前 uid: ' + process.getuid());
try {
process.setuid(501);
console.log('新 uid: ' + process.getuid());
}
catch (err) {
console.log('设置 uid 失败: ' + err);
}
}
process.getgroups()#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
返回一个保存补充组ID(supplementary group ID)的数组。POSIX 标准没有指名 如果有效组 ID(effective group ID)被包括在内的情况,而在 node.js 中则确保它始终是。(POSIX leaves it unspecified if the effective group ID is included but node.js ensures it always is. )
process.setgroups(groups)#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
设置补充分组的ID标识. 这是一个特殊的操作, 意味着你必须拥有root或者CAP_SETGID权限才可以。(译者:CAP_SETGID表示设定程序允许普通用户使用setgid函数,这与文件的setgid权限位无关)
这个列表可以包括分组的ID表示,或分组名或两者都有。
process.initgroups(user, extra_group)#
注意: 该函数仅适用于遵循 POSIX 标准的系统平台如 Unix、Linux等 而 Windows、 Android 等则不适用。
读取 /etc/group 并且初始化group分组访问列表,使用改成员所在的所有分组, 这是一个特殊的操作, 意味着你必须拥有root或者CAP_SETGID权限才可以。
user
是一个用户名或者用户ID. extra_group
是分组的组名或者分组ID。
有时候,当你在注销权限 (dropping privileges) 的时候需要注意。例如:
console.log(process.getgroups()); // [ 0 ]
process.initgroups('bnoordhuis', 1000); // switch user
console.log(process.getgroups()); // [ 27, 30, 46, 1000, 0 ]
process.setgid(1000); // drop root gid
console.log(process.getgroups()); // [ 27, 30, 46, 1000 ]
process.version#
一个暴露编译时存储版本信息的内置变量 NODE_VERSION
的属性。
console.log('版本: ' + process.version);
process.versions#
一个暴露存储 node 以及其依赖包 版本信息的属性。
console.log(process.versions);
输出:
{ http_parser: '1.0',
node: '0.10.4',
v8: '3.14.5.8',
ares: '1.9.0-DEV',
uv: '0.10.3',
zlib: '1.2.3',
modules: '11',
openssl: '1.0.1e' }
process.config#
一个包含用来编译当前 node.exe 的配置选项的对象。内容与运行 ./configure
脚本生成的 "config.gypi" 文件相同。
最可能的输出示例如下:
{ target_defaults:
{ cflags: [],
default_configuration: 'Release',
defines: [],
include_dirs: [],
libraries: [] },
variables:
{ host_arch: 'x64',
node_install_npm: 'true',
node_prefix: '',
node_shared_cares: 'false',
node_shared_http_parser: 'false',
node_shared_libuv: 'false',
node_shared_v8: 'false',
node_shared_zlib: 'false',
node_use_dtrace: 'false',
node_use_openssl: 'true',
node_shared_openssl: 'false',
strict_aliasing: 'true',
target_arch: 'x64',
v8_use_snapshot: 'true' } }
process.kill(pid, [signal])#
向进程发送一个信号。 pid
是进程的 id 而 signal
则是描述信号的字符串名称。信号的名称都形似 'SIGINT' 或者 'SIGUSR1'。如果没有指定参数则会默认发送 'SIGTERM' 信号,更多信息请查看 kill(2) 。
值得注意的是,这个函数的名称虽然是 process.kill
, 但就像 kill
系统调用(详见《Unix高级编程》)一样,它仅仅只是一个信号发送器。而信号的发送不仅仅只是用来杀死(kill)目标进程。
向当前进程发送信号的示例:
process.kill(process.pid, 'SIGHUP');
process.pid#
当前进程的 PID
console.log('当前进程 id: ' + process.pid);
process.title#
获取/设置 (Getter/setter) 'ps' 中显示的进程名。
当设置该属性时,所能设置的字符串最大长度视具体平台而定,如果超过的话会自动截断。
在 Linux 和 OS X 上,它受限于名称的字节长度加上命令行参数的长度,因为它有覆盖参数内存(argv memory)。
v0.8 版本允许更长的进程标题字符串,也支持覆盖环境内存,但是存在潜在的不安全和混乱(很难说清楚)。
process.arch#
返回当前 CPU 处理器的架构:'arm'、'ia32' 或者 'x64'.
console.log('当前CPU架构是:' + process.arch);
process.platform#
返回当前程序运行的平台:'darwin'
, 'freebsd'
, 'linux'
, 'sunos'
或者 'win32'
console.log('当前系统平台是: ' + process.platform);
process.memoryUsage()#
返回一个对象,它描述了Node进程的内存使用情况单位是bytes。
console.log(util.inspect(process.memoryUsage()));
输出将会是:
{ rss: 4935680,
heapTotal: 1826816,
heapUsed: 650472 }
heapTotal
和 heapUsed
是根据 V8引擎的内存使用情况来的
process.nextTick(callback)#
callback
{Function}
在事件循环的下一次循环中调用 callback 回调函数。
这 不是 setTimeout(fn, 0)
函数的一个简单别名,因为它的效率高多了。该函数能在任何 I/O 事前之前调用我们的回调函数。但是这个函数在层次超过某个限制的时候,也会出现瑕疵,详细见 process.maxTickDepth
。
console.log('开始');
process.nextTick(function() {
console.log('nextTick 回调');
});
console.log('已设定');
// 输出:
// 开始
// 已设定
// nextTick 回调
如果你想要在【对象创建】之后而【I/O 操作】发生之前执行某些操作,那么这个函数对你而言就十分重要了。
// thing.startDoingStuff() 现在被调用了, 而不是之前.
【注意!!】保证你的函数一定是同步执行或者一定是异步执行,这非常重要!!参考如下的例子:
fs.stat('file', cb);
}
这样执行是很危险。如果你还不清楚上述行为的危害请看下面的例子:
maybeSync(true, function() {
foo();
});
bar();
那么,使用刚才那个不知道是同步还是异步的操作,在编程的时候你就会发现,你不能确定到底是 foo() 先执行,还是 bar() 先执行。
用下面的方法就可以更好的解决:
fs.stat('file', cb);
}
注意:nextTick 的队列会在完全执行完毕之后才调用 I/O 操作 (the nextTick queue is completely drained on each pass of the event loop before additional I/O is processed.) 。因此,递归设置 nextTick 的回调就像一个 while(true) ;
循环一样,将会阻止任何 I/O 操作的发生。
process.umask([mask])#
设置或者读取进程的文件模式的创建掩码。子进程从父进程中继承这个掩码。如果设定了参数 mask 那么返回旧的掩码,否则返回当前的掩码。
oldmask = process.umask(newmask);
console.log('原掩码: ' + oldmask.toString(8) + '\n'
'新掩码: ' + newmask.toString(8));
process.uptime()#
返回 Node 程序已运行的秒数。
process.hrtime()#
返回当前的高分辨时间,形式为 [秒,纳秒]
的元组数组。它是相对于在过去的任意时间。该值与日期无关,因此不受时钟漂移的影响。主要用途是可以通过精确的时间间隔,来衡量程序的性能。
你可以将前一个 process.hrtime()
的结果传递给当前的 process.hrtime()
函数,结果会返回一个比较值,用于基准和衡量时间间隔。
console.log('基准相差 %d 纳秒', diff[0] * 1e9 + diff[1]);
// 基准相差 1000000527 纳秒
}, 1000);
utils#
稳定度: 4 - 冻结
如果你想使用模块 'util'
中已定义的方法. 只需 require('util')
即可使用.
util
模块设计的主要目的是为了满足Node内部API的需求 。这个模块中的很多方法在你编写Node程序的时候都是很有帮助的。如果你觉得提供的这些方法满足不了你的需求,那么我们鼓励你编写自己的实用工具方法。我们 不希望util
模块中添加任何对于Node的内部功能非必要的扩展。
util.debuglog(section)#
section
{String} 被调试的程序节点部分- 返回值: {Function} 日志处理函数
这个方法是在存在NODE_DEBUG
环境变量的基础上,创建一个有条件写到stderr里的函数。如果“节点”的名字出现在这个环境变量里,那么就返回一个功能类似于console.error()
的函数.如果不是,那么返回一个空函数.
例如:
var bar = 123; debuglog('hello from foo [%d]', bar);
<!-- endsection -->
<!-- section:841c12a486aeca12985eeae2d550044e -->
如果这个程序以`NODE_DEBUG=foo` 的环境运行,那么它将会输出:
<!-- endsection -->
<!-- section:cefee92825ed4220569779223fcc49f3 -->
FOO 3245: hello from foo [123]
<!-- endsection -->
<!-- section:17ef1e93428ebec32b98fa8fe18e7807 -->
`3245`是进程的ID, 如果程序不以刚才那样设置的环境变量运行,那么将不会输出任何东西。
<!-- endsection -->
<!-- section:fb8af07a0bc0e884ec481501fb9ee17d -->
多个`NODE_DEBUG`环境变量,你可以用逗号进行分割。例如,`NODE_DEBUG= fs, net, tls`。
<!-- endsection -->
<!-- section:1785afa5e0b057aea818cd8bc131248a -->
## util.format(format, [...])
<!-- endsection -->
<!-- section:91ee7971cb6dbe7c7841d5c0357a625a -->
根据第一个参数,返回一个格式化字符串,类似`printf`的格式化输出。
<!-- endsection -->
<!-- section:eed068a3508e3b9cc687607e97338b9f -->
第一个参数是一个字符串,包含零个或多个*占位符*。
每一个占位符被替换为与其对应的转换后的值。
支持的占位符有:
<!-- endsection -->
<!-- section:da9b014604572a67a757e892ddd36dd3 -->
* `%s` - 字符串.
* `%d` - 数字 (整型和浮点型).
* `%j` - JSON. 如果这个参数包含循环对象的引用,将会被替换成字符串 `'[Circular]'`。
* `%%` - 单独一个百分号(`'%'`)。不会消耗一个参数。
<!-- endsection -->
<!-- section:c2996cb0cabc702cd8d2bf9d2410599b -->
如果占位符没有相对应的参数,占位符将不会被替换。
<!-- endsection -->
<!-- section:8b6a9f474a82c2495887bf9fe6602308 -->
util.format('%s:%s', 'foo'); // 'foo:%s'
<!-- endsection -->
<!-- section:1e95291ba804f022549694a216ac10c6 -->
如果有多个参数占位符,额外的参数将会调用`util.inspect()`转换为字符串。这些字符串被连接在一起,并且以空格分隔。
<!-- endsection -->
<!-- section:ba9ecf5f8b441a986c81bee295e7f5f6 -->
util.format('%s:%s', 'foo', 'bar', 'baz'); // 'foo:bar baz'
<!-- endsection -->
<!-- section:f34f71da627ffc546bb170512e2ffa99 -->
如果第一个参数是一个非格式化字符串,那么`util.format()`将会把所有的参数转成字符串,以空格隔开,拼接在一块,并返回该字符串。`util.inspect()`会把每个参数都转成一个字符串。
<!-- endsection -->
<!-- section:25dcc02c2222a4275231d90579c8598e -->
util.format(1, 2, 3); // '1 2 3'
<!-- endsection -->
<!-- section:f695fcc4f18f5c6e339ccce4e3389dcf -->
## util.log(string)
<!-- endsection -->
<!-- section:726d139874d57d83bf5da6c193940e4d -->
在控制台进行输出,并带有时间戳。
<!-- endsection -->
<!-- section:ba5cd1d0dee4eb1d7de5808ac9c816b8 -->
示例:require('util').log('Timestamped message.');
<!-- endsection -->
<!-- section:49290ff385e98b889e7199f35d8fdd82 -->
## util.inspect(object, [options])
<!-- endsection -->
<!-- section:1109f4d3eef77037e85144a6ac35edb4 -->
返回一个对象的字符串表现形式, 在代码调试的时候非常有用.
<!-- endsection -->
<!-- section:258dc184e5a4c8130e86a263acb47331 -->
可以通过加入一些可选选项,来改变对象的格式化输出形式:
<!-- endsection -->
<!-- section:e8f8d3d45f5ea0449c8466bcc7d1aef5 -->
- `showHidden` - 如果设为 `true`,那么该对象的不可枚举的属性将会被显示出来。默认为`false`.
<!-- endsection -->
<!-- section:961283759790f15496ef9cfd71e80da0 -->
- `depth` - 告诉 `inspect` 格式化对象的时候递归多少次。这个选项在格式化复杂对象的时候比较有用。 默认为
`2`。如果想无穷递归下去,则赋值为`null`即可。
<!-- endsection -->
<!-- section:87002282463d3e4ae824462785cdb97f -->
- `colors` - 如果设为`true`,将会以`ANSI`颜色代码风格进行输出.
默认是`false`。颜色是可定制的,请看下面:
<!-- endsection -->
<!-- section:e58f864e5d78935059b0d82a0de99ac5 -->
- `customInspect` - 如果设为 `false`,那么定义在被检查对象上的`inspect(depth, opts)` 方法将不会被调用。 默认为`