您正在查看: Node.js 分类下的文章

The NodeJS URL模块

URL模块

此模块用于解析URL,你可以通过require('url')来使用它。

由于各URL 不尽相同,经过解析的URL 对象有如下部分或者全部的域。任何URL 中不包含的域将不会出现在
解析后的URL 对象中。如下所示:
'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'

href

原始的URL。例如:'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'

protocol

请求的协议。例如:'http'

host

URL 中主机地址部分,包括端口和验证信息。例如:'user:pass@host.com:8080'

auth

URL 中的验证信息。例如:'user:pass'

hostname

仅仅包括主机地址。例如:'host.com'

port

主机的端口号。例如:'8080'

pathname

URL 中的路径(path)部分,即紧跟在主机地址之后查询参数之前的部分,包括路径开头的斜线。例如:'/p/a/t/h'

search

URL 中的参数部分,包括开头的问号。例如:?query=string

query

查询字符串中的参数部分或者是解析过的查询字串对象(译注:根据解析URL 时设置的参数不同,此属性的内
容也不同)。例如:'query=string' 或者{'query':'string'}

hash

URL 中的锚记部分,包括开头的井号。例如:'#hash'
URL 模块还提供如下方法:

url.parse(urlStr, parseQueryString=false)

此函数接受一个URL 字符串并返回一个对象。如果第二个参数传递true,node 会使用querystring 模块解析查询
字符串。

url.format(urlObj)

此函数接受一个URL 对象,并返回一个格式化后的URL 字符串。

url.resolve(from, to)

此函数接受一个base URL 和一个href URL,并像浏览器解析锚记一样解析它们。

The NodeJS REPL 交互执行

REPL 交互执行

node 的“读入、运行、输出循环模式(REPL)”既可以单独执行也很容易嵌入其它程序中。REPL 提供了一种交互
式执行javascript 并查看结果的模式。这种模式可以用来调试、测试或者仅仅用来某些新特性。

如果直接执行node 而不跟任何参数就会进入REPL 模式。它类似于简化的emacs 行编辑模式。

mjr:~$ node
Type '.help' for options.
node> a = [ 1, 2, 3];
[ 1, 2, 3 ]
node> a.forEach(function (v) {
... console.log(v);
... });
1
2
3```

要使用高级行编辑功能,设置环境变量NODE_NO_READLINE=1并执行node。这样REPL 就会使用标准终端
设置,如此一来你就可以使用rlwarp 来执行高级行编辑。
示例,你可以在bashrc 文件中添加如下指令:

alias node="env NODE_NO_READLINE=1 rlwrap node"
repl.start(prompt='node> ', stream=process.openStdin())```

REPL 执行时将使用prompt 参数的值作为输入提示符,并使用stream 参数执行所有I/O 操作。prompt 为可选
参数,默认值为'node>', stream 为可选参数,默认值为process.openStdin();

同一个node 进程可以启动多个REPL,每个REPL 将会共享部分全局对象,但是它们都有自己唯一的I/O。
示例,分别使用标准输出(控制台)、Unix Socket 和TCP Socket 启动REPL:

var net = require("net"),
repl = require("repl");
connections = 0;
repl.start("node via stdin> ");
net.createServer(function (socket) {
connections += 1;
repl.start("node via Unix socket> ", socket);
}).listen("/tmp/node-repl-sock");
net.createServer(function (socket) {
connections += 1;
repl.start("node via TCP socket> ", socket);
}).listen(5001);```

在控制台执行上述程序将使用标准输入(当前控制台)启动REPL,同时其他REPL 客户端可以通过Unix socket
或者TCP socket 连接。你可以使用telnet 连接到TCP socket,用socat 连接到Unix 或TCP sockets。
不使用标准输入(控制台)而是用Unix socket 服务启动REPL,可以让你轻易连接到一个长时间运行的node 进
程而不用重新启动该进程。


**REPL Features REPL支持的特性**


在REPL 执行时,可以输入Control+D 退出。你也可以输入跨越多行的表达式。
特殊标量'_'(下划线)保存了上一个表达式执行后的值。

node> [ "a", "b", "c" ]
[ 'a', 'b', 'c' ]
node> _.length
3
node> _ += 1
4```

REPL 提供了访问全局作用域内任何变量的能力,你也可以通过将变量赋值给REPL 的context 对象来向REPL
暴露该变量。例如:

// repl_test.js
var repl = require("repl"),
msg = "message";
repl.start().context.m = msg;
对于REPL 来说,context 对象中的值就犹如在本地作用域内:
mjr:~$ node repl_test.js
node> m
'message'```

如下是一些REPL 命令:


.break - 当想要放弃当前输入的多行命令时,可以使用.break 命令重新开始输入。

.clear - 将context 重置为空对象并清空(当前正在输入的)多行表达式。


.exit - 管理I/O 流,此操作将关闭REPL。


.help - 显示特殊命令的帮助。

The NodeJS Script 脚本

Script 脚本

Script 类可以编译执行javascript 代码。你可以用以下方式访问Script 类:

var Script = process.binding('evals').Script;```

javascript 代码可以被编译、立刻执行或者编译、保存、延时执行。


**Script.runInThisContext(code, [filename])**


同process.compile 函数类似,Script.runInThisContext 函数编译执行code 参数包含的代码并返回结果,就如同这
些代码是从filename 参数指定文件中加载的一样。这些代码不能访问本地作用域。filename 参数是可选的。(译
注:filename 参数的作用是为了更好的输出错误信息)


示例:演示使用Script.runInThisContext 函数和eval 函数执行同一段代码:

var localVar = 123,
usingscript, evaled,
Script = process.binding('evals').Script;
usingscript = Script.runInThisContext('localVar = 1;',
'myfile.js');
console.log('localVar: ' + localVar + ', usingscript: ' +
usingscript);
evaled = eval('localVar = 1;');
console.log('localVar: ' + localVar + ', evaled: ' +
evaled);
// localVar: 123, usingscript: 1
// localVar: 1, evaled: 1```

Script.runInThisContext 函数执行的代码并不访问本地作用域,所以localVar 变量的值并没有改变。eval 函数执
行的代码可以访问本地作用域,所以localVal 的值被改变了。

如果代码有语法错误,Script.runInThisContext 会输出错误信息到控制台(stderr)并抛出异常。

Script.runInNewContext(code, [sandbox], [filename])

Script.runInNewContext 将代码编译并在sandbox 参数指定的作用域内执行代码并返回结果,就如同代码是从文
件中加载的一样。执行的代码并不访问本地作用域,sandbox 参数指定的对象将作为代码执行的全局对象。
sandbox 和filename 参数都是可选的。

例子:编译并执行一段代码,这段代码递增并新建一个全局变量。这些全局变量都保存在sandbox 中。

var sys = require('sys'),
Script = process.binding('evals').Script,
sandbox = {
animal: 'cat',
count: 2
};
Script.runInNewContext(
'count += 1; name = "kitty"', sandbox, 'myfile.js');
console.log(sys.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }```

请注意,执行不信任的代码(untrusted code)是一项需要技巧的工作。Script.runInNewContext 函数非常有用,它可
以在一个独立的线程中执行不信任的代码防止全局变量被意外修改。


如果代码有语法错误,Script.runInThisContext 会输出错误信息到控制台(stderr)并抛出异常。


**new Script(code, [filename])**


新建Script 对象会编译code 参数指定的代码,就如同代码是从filename 参数指定的文件中加载的一样。和其他
函数不同的是,它将返回一个代表经过编译的代码的Script 对象,这个对象可以使用下面介绍的函数执行内部
编译好的代码。这个script 对象并不绑定到任何全局对象,但是可以在运行时绑定到指定对象,每次绑定仅在
本次运行时生效。filename 参数是可选的。


如果代码有语法错误,new Script emits 会输出错误信息到控制台(stderr)并抛出异常。


**script.runInThisContext()**


这个函数和Script.runInThisContext 函数类似(对象名首字母'S'的大小写不同),不同的是此函数是Script 对象的
方法。script.runInThisContext 函数执行对象中的代码并返回结果。执行的代码并不会访问本地作用域,但是可
以访问全局作用域(v8: in actual context)。


例子:使用script.runInThisContext 函数实现代码的一次编译多次执行。

var Script = process.binding('evals').Script,
scriptObj, i;
globalVar = 0;
scriptObj = new Script('globalVar += 1', 'myfile.js');
for (i = 0; i < 1000 ; i += 1) {
scriptObj.runInThisContext();
}
console.log(globalVar);
// 1000```
script.runInNewContext([sandbox])

此函数和Script.runInNewContext 函数类似(对象名首字母'S'的大小写不同),不同的是此函数是Script 对象的
方法。script.runInNewContext 函数将sandbox 参数指定的对象作为全局对象执行代码,并返回结果。执行的代
码并不访问本地作用域。sandbox 参数是可选的。

例子:编译并执行一段代码,这段代码递增并新建一个全局变量,这些全局变量都保存在sandbox 中。然后多次执行这段代码,这些全局变量都保存在沙盒(sandbox)中。

var sys = require('sys'),
Script = process.binding('evals').Script,
scriptObj, i,
sandbox = {
animal: 'cat',
count: 2
};
scriptObj = new Script(
'count += 1; name = "kitty"', 'myfile.js');
for (i = 0; i < 10 ; i += 1) {
scriptObj.runInNewContext(sandbox);
}
console.log(sys.inspect(sandbox));
// { animal: 'cat', count: 12, name: 'kitty' }```

请注意,执行不信任的代码(untrusted code)是一项需要技巧的工作。script.runInNewContext 函数非常有用,它可
以在一个单独的线程中执行不信任的代码防止全局变量被意外修改。

####File System 文件系统
(注:同步与异步方式是指同步或异步于程序执行,并非函数彼此之间的同步关系。)
文件的I/O 是由标准POSIX 函数封装而成。需要使用"require('fs')"操作这个类。所有的方法设有异步方式和同步
方式。


异步形式下的方法其最后一个参数,总是一个完整的回调函数(callback)。这个回调函数有那些参数,就取决
于异步方法怎么送入参数,但通常来说,第一个送入的参数是异常对象。如果是没有任何问题的操作,那么这
个异常对象就变为null 或者undefined,表示操作正常。
异步方式的例子:


var fs = require('fs');
fs.unlink('/tmp/hello', function (err) {
if (err) throw err;
console.log('successfully deleted /tmp/hello');
});```

同步方式的例子:

var fs = require('fs');
fs.unlinkSync('/tmp/hello')
console.log('successfully deleted /tmp/hello');```

异步函数没有一定的顺序,所以以下例子容易发生错误:

fs.rename('/tmp/hello', '/tmp/world', function (err) {
if (err) throw err;
console.log('renamed complete');
});
fs.stat('/tmp/world', function (err, stats) {
if (err) throw err;
console.log('stats: ' + JSON.stringify(stats));
});```

这有可能fs.state 于fs.rename 前执行。正确的做法是嵌套回传函数。

fs.rename('/tmp/hello', '/tmp/world', function (err) {
if (err) throw err;
fs.stat('/tmp/world', function (err, stats) {
if (err) throw err;
console.log('stats: ' + JSON.stringify(stats));
});
});```

当执行动作繁杂时,强烈建议使用异步方式调用此类。同步方式在其完成之前将会阻挡一切随后的动作,这代
表搁置所有连接。


**fs.rename(path1, path2, [callback])**


异步命名(rename(2))。只传递异常给回调函数。


**fs.renameSync(path1, path2)**


同步命名(rename(2))。

**fs.truncate(fd, len, [callback])**


异步截断(ftruncate(2))。只传递异常给回调函数。


**fs.truncateSync(fd, len)**


同步截断(ftruncate(2))。


**fs.chmod(path, mode, [callback])**


异步更改文件权限(chmod(2))。只传递异常给回调函数。

**fs.chmodSync(path, mode)**


同步更改文件权限(chmod(2))。


**fs.stat(path, [callback])**


利用路径异步读取属性(stat(2))。回调函数的第二个参数是fs.Stats 对象(err, stats),例如:

{ dev: 2049
, ino: 305352
, mode: 16877
, nlink: 12
, uid: 1000
, gid: 1000
, rdev: 0
, size: 4096
, blksize: 4096
, blocks: 8
, atime: '2009-06-29T11:11:55Z'
, mtime: '2009-06-29T11:11:40Z'
, ctime: '2009-06-29T11:11:40Z'
}```

参考fs.Stats 部份以取得详细资料。

fs.lstat(path, [callback])

利用路径异步读取属性(lstat(2))。如果这个文件参数是一个符号连接,则返回该符号连接的属性。回调函数的第
二个参数是fs.Stats 对象。(err, stats)

fs.fstat(fd, [callback])
利用存在的指标异步读取属性(fstat(2))。回调函数的第二个参数是fs.Stats 对象。(err, stats)

fs.statSync(path)

同步读取属性(stat(2))。返回fs.Stats。

fs.lstatSync(path)

利用路径同步读取属性(lstat(2))。返回fs.Stats。

fs.fstatSync(fd)

利用存在的指标同步读取属性(fstat(2))。返回fs.Stats。

fs.link(srcpath, dstpath, [callback])

异步建立连接(link(2))。只传递异常给回调函数。

fs.linkSync(dstpath, srcpath)

同步建立连接(link(2))。

fs.symlink(linkdata, path, [callback])

异步建立符号连接(symlink(2))。只传递异常给回调函数。

fs.symlinkSync(linkdata, path)

同步建立符号连接(symlink(2))。

fs.readlink(path, [callback])

异步读取连接(readlink(2))。回调函数的第二个参数是已解析的文件路径。(err, resolvedPath)

fs.readlinkSync(path)

同步读取连接(readlink(2))。返回已解析的文件路径。

fs.realpath(path, [callback])

异步读取絶对的路径名称(realpath(2))。回调函数的第二个参数是已解析的文件路径。(err, resolvedPath)

fs.realpathSync(path)

同步读取絶对的路径名称(realpath(2))。返回已解析的文件路径。

fs.unlink(path, [callback])

异步删除连接(~=删除文件)(unlink(2))。只传递异常给回调函数。

fs.unlinkSync(path)

同步删除连接(~=删除文件)(unlink(2))。

fs.rmdir(path, [callback])

异步删除目录(rmdir(2))。只传递异常给回调函数。

fs.rmdirSync(path)

同步删除目录(rmdir(2))。

fs.mkdir(path, mode, [callback])

异步建立目录(mkdir(2))。只传递异常给回调函数。

fs.mkdirSync(path, mode)

同步建立目录(mkdir(2))。

fs.readdir(path, [callback])

异步读取目录中的内容(readdir(3))。回调函数的第二个参数是以阵列构成的目录内对象的名称('.'与'..'除外)。(err,
files)

fs.readdirSync(path)

同步读取目录中的内容(readdir(3))。返回以阵列构成的目录内对象名称('.'与'..'除外)。

fs.close(fd, [callback])

异步结束(close(2))。只传递异常给回调函数

fs.closeSync(fd)

同步结束(close(2))。

fs.open(path, flags, mode=0666, [callback])

异步开启文件,详阅open(2)。标签可为'r', 'r+', 'w', 'w+', 'a', 或'a+'。回调函数的第二个参数是指标。(err, fd)

fs.openSync(path, flags, mode=0666)

同步开启文件。

fs.write(fd, buffer, offset, length, position, [callback])

透过指标(fd)写入缓冲区至文件。
offset 偏移 和 length 长度 决定哪一部份的缓冲区被写入。

position 写入位置 若 position 为空,则写入至现存位置。详阅 pwrite(2)。
回调函数的第二个参数是写入动作的数据大小(bytes)。(err, written)

fs.writeSync(fd, buffer, offset, length, position)

fs.write(缓冲区)的同步方式。返回写入动作的数据大小。

fs.writeSync(fd, str, position, encoding='utf8')

fs.write(字串)的同步方式。返回写入动作的数据大小。

fs.read(fd, buffer, offset, length, position, [callback])

透过指标(fd)读取数据。

buffer 是读取的数据的存放位置。

offset 是标注哪里开始写入缓冲区。

length 是以整数型态(INT)标注读取的数据大小。

position 是以整数型态(INT)标注文件的读取位置。若 position 为空,则由现存位置读取。
回调函数的第二个参数是读取动作的数据大小(bytes)。(err, bytesRead)

fs.read(fd, length, position, encoding, [callback])

透过指标(fd)读取数据。

length 是以整数型态(INT)标注读取的数据大小。

position 是以整数型态(INT)标注文件的读取位置。若
position 为空,则由现存位置读取。

encoding 是读取数据的预期编码。
回调函数的第二个参数是读数的数据而第三个参数是读取动作的数据大小(bytes)。(err, str, bytesRead)

fs.readSync(fd, buffer, offset, length, position)

fs.read(缓冲区)的同步方式。返回读取动作的数据大小。

fs.readSync(fd, length, position, encoding)

fs.read(字串)的同步方式。返回读取动作的数据大小。

fs.readFile(filename, [encoding], [callback])

透过文件路径异步读取内容,例子:

fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});```

回调函数的第二个参数是文件内容。(err, datad)
若编码(encoding)没有被指定,则返回原始缓冲区。


**fs.readFileSync(filename, [encoding])**


fs.readFile()的同步方式。返回文件内容。


若编码(encoding)被指定,则返回字串,反之则返回原始缓冲区。


**fs.writeFile(filename, data, encoding='utf8', [callback])**

异步写入数据至文件,data(数据)可以为字串或缓冲区。
例子:

fs.writeFile('message.txt', 'Hello Node', function (err) {
if (err) throw err;
console.log('It's saved!');
});```

fs.writeFileSync(filename, data, encoding='utf8')

fs.writeFile()的同步方式。

fs.watchFile(filename, [options], listener)

观察文件异变。文件异动时会触发监听函数。

第二个参数是可选的。选项(options)参数应为对象(object),当中包含一布林值(BOOL)持续检查(persistent)与检测
相隔时间(interval)(单位为毫秒)。

传递给监听函数的参数分别是当前状态对象(curr)以及前次状态对象(prev)。

fs.watchFile(f, function (curr, prev) {
console.log('the current mtime is: ' + curr.mtime);
console.log('the previous mtime was: ' + prev.mtime);
});```

stat 对象是fs.Stat 的实例。


**fs.unwatchFile(filename)**


停止观察文件异变。

The NodeJS Standard Modules 标准模块

Standard Modules 标准模块

node 附带了一些模块,这些模板都被编译进了node 二进制文件中,其中大部分将在下文介绍。使用这些模块
最常见的方法是调用“require('name')”并将返回值赋给一个和模块同名的局部变量。
例如:

var sys = require('sys');```

同样可以使用其他模块扩展node。详情参看"模块"章节。

The NodeJS Streams 流

Streams 流

stream 是一个抽象接口,node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是
一个stream,还有stdout(标准输出)。Stream 可以是只读、可写,也可以同时可读可写。所有的Stream 对象
都是EventEmitter 的实例。

##Readable Stream 只读流

一个只读流有如下方法、成员、和事件。

Event: 'data'

function (data) { }```


'data'事件的参数是Buffer(默认情况下),如果调用过setEncoding()方法,则参数为一个字符串。


**Event: 'end'**

function () { }```

此事件在流遇到EOF(在TCP 中为FIN)时被触发,表示该流不会再有数据(不会再次触发'data'事件)。如果该流
也是可写流,则它还可以继续写入。

Event: 'error'

function (exception) { }```

在收取数据出错时被触发。


**Event: 'close'**

function () { }```

内部的文件描述符被关闭时被触发,并不是所有的流都会触发此事件。(例如,一个进入的(incoming)HTTP 请
求将不会触发'close'事件)。

Event: 'fd'

function (fd) { }

当数据流接收到文件描述符信息时触发该事件(一个文件数据流包含两部分信息:文件描述符信息和文件的数
据信息)。本事件只支持Unix 数据流,其他类型的流不会触发该事件。

stream.readable

一个布尔值,默认为true。当遇到错误或流读到结尾或者调用destory()函数后,该值被设置为false。

stream.setEncoding(encoding)

该函数设置data 事件返回字符串而不是Buffer 对象。编码类型可以设置为"utf8","ascii"或"base64"。

stream.pause()

暂停触发data 事件。

stream.resume()

恢复触发'data'事件。

stream.destroy()

关闭内部的文件描述符。这样该流将不会再触发任何事件。

##Writable Stream 可写流

一个可写流具备以下方法、成员、和事件。

Event: 'drain'

function () { }```

在一个wrire() 方法被调用并返回false 后触发,表明可以安全的再次写入该stream。


**Event: 'error'**

function (exception) { }


在异常发生赤错误时被触发。

**Event: 'close'**

function () { }```

当底层的文件描述符已终止时发出。

stream.writeable

一个boolean 值,缺省为true ,但是在一个'error'产生或是end() / destroy() 被调用后,会变为false 。

stream.write(string, encoding='utf8', [fd])

使用指定的编码将字符串字符串写入到流中。如果字符串已被刷新到内核缓冲区,返回true。返回false 则表明
内核缓冲区已满,数据将在未来被发送出去。'drain'事件用来通知内核缓冲区何时为空。此方法的默认编码为
'utf8'。

如果指定了可选参数fd,它将被当做一个文件描述符并通过流来发送。它只支持UNIX 流,否则会被忽略且没
有任何提示。当用这种方式发送文件描述符时,在流清空之前关闭文件描述符可能导致发送出非法的描述符。

stream.write(buffer)

同上,除了使用一个原始缓冲区。

stream.end()

通过EOF 或FIN 来终止流。

stream.end(string, encoding)

根据指定的编码发送字符串,并通过EOF 或FIN 来终止流。这对于减少发送数据包的数量是非常有用的。

stream.end(buffer)

同上,但使用一个缓冲区。

stream.destroy()

终止底层的文件描述符,此后流不再发出任何事件。