Node.js API实例讲解——其他工具模块
其他工具模块
定时器
node.js 提供了setTimeout定时器方式,对应清除定时器的方法是 clearTimeout。
这里没有介绍 setInterval,因为其不确定性和诸多问题,这里不进行详说。所以下一个定论,不要再任何时候使用 setInterval。
定时器的意思就是,设定一个倒计时,时间一到就执行指定的函数。
看下面例子:
function test(){ console.log("hello"); } setTimeout(test,3000); console.log("lol");
先打印出“lol”,等待大约3000后,执行test函数,打印出“hello”。这里为什么用大约呢?因为虽然设置了3秒,但系统如果忙碌会推迟执行test。
clearTimeout是清除定时器的方法,看下面代码:
function test(){ console.log("hello"); } var time = setTimeout(test,3000); clearTimeout(time); console.log("lol");
setTimeout方法会返回一个id值,通过clearTimeout(id)就可清除该监听器。所以这段代码只会打印出lol。
setTimeout还可以为定时器方法传递参数,看下面例子:
function test(name){ console.log("hello ",name); } var time = setTimeout(test,3000,"brighthas"); console.log("lol");
打印结果:
lol hello brighthas
node.js 还提供了一个 setImmediate方法,该方法不是定时器,它的作用类似于 setTimeout(test,0),定时为0 时,并不会马上执行,系统内部会设定最小值 > 0 。
可以简单理解为 setImmediate 的性能要比 setTimeout(... , 0) 好很多。看下面例子:
function test(name){ console.log("hello ",name); } var time = setImmediate(test,"brighthas"); console.log("lol");
打印结果:
lol hello brighthas
setImmediate方法也会返回一个id,通过clearImmeiate(id) 方式删除。
util模块
util是个工具箱,有一些很有用处的工具,下面进行介绍。
var util = require("util") 导入模块。
util.format(str, [...])
这个方法会把字符串格式化后返回
第一个参数是一个字符串,其中包含零个或多个占位符。每一个占位符被替换其相应的参数。如果占位符没有相应的参数,将占位符不会被替换,而是直接打印出占位符的字面量。
支持的占位符:
%s - 字符串。look
%d - 数字(包括整数和浮点数)。
%j - JSON。good
测试1,只有第一个参数的情况。
util.format("hello world"); // hello world
测试2,具有占位符,但后面无对应参数。
util.format("hello %s"); // hello %s
测试3,具有占位符,后面对应相关参数。
util.format("hello %s","world!!"); // hello world!! util.format("1+1 = %d",2); // 打印出 1+1 = 2 util.format("a json object : %j",{bookAuthor:"brighthas"}); // 打印出 a json object : {"bookAuthor":"brighthas"}
测试4,多个参数。
util.format("aa","bb","cc"); // 打印出 aa bb cc , 之间有一个空格。 util.format("aa %d%s",121,"bbb") // 打印出 aa 121bbb util.format("aa %d%s","ccc","bbb") // 打印出 aa NaNbbb 我们会看到 ccc 参数被转换为NaN, // 说明内部会根据占位符类型转换相应的参数。
util.debug(string)
这个方法是把字符串信息同步输出到stderr。
util.debug("have a bug.");
打印出:
DEBUG: have a bug.
util.error([...])
这个方法是把字符串信息输出到stderr,可以输入多个字符串。
util.error("aaa","bbb","ccc");
打印结果:
aaa bbb ccc
util.puts([...])
这个方法是把字符串信息同步输出到stdout,可以输入多个字符串。
util.puts("aaa","bbb","ccc");
打印结果:
aaa bbb ccc
util.print([...])
这个方法是把字符串信息同步输出到stdout,可以输入多个字符串,打印在一行显示。
util.print("aaa","bbb","ccc");
打印结果:
aaabbbccc
util.log(string)
这个方法是把字符串信息输出到stdout,并且前面加上发布时间。
util.log("abc")
打印结果:
12 Apr 09:51:27 - abc
util.inspect(object, [options])
这个方法是返回javascript对象的字符串形式,第二个参数是可选项。
options { showHidden 参数默认false,true表示打印出非枚举属性 depth 查询对象深度默认2,depath设置为null表示无限深度(一查到底), colors选项默认false,true表示颜色显示}
看下面例子:
例1
function User(name){ this.name = name; } var u = new User("leo"); var util = require("util"); console.log(util.inspect(u,{colors:true}));
打印出:
{name:'leo'}
其中 leo 是带有颜色的。
util.isArray(object)
sex判断对象是否是数组类型sex
util.isRegExp(object)
判断对象是否是正则类型
util.isDate(object)
判断对象是否是日期类型
util.isError(object)
判断对象是否是Error类型
util.inherits(constructor, superConstructor)
继承prototype ,这里显示一下util.inherits源代码:
exports.inherits = function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); };
下面举个例子:
function A(){} A.prototype.abc = function(){} function B(){} var util = require("util"); util.inherits(B,A); console.log(B.prototype.abc);
这样B.prototype 就具有了abc方法。
domain模块
domain模块的意义是建立一个环境,在这个域环境内的代码如果有异步或同步错误都可以统一处理。下面举个例子:
var Domain = require("domain"); var domain = Domain.create(); domain.on("error",function(){ console.log("有个错误") }); domain.run(function(){ throw new Error("错误!!!"); })
运行后打印出 "有个错误"。
有人说这个好办,用 try ... catch 也可以做到,但如果是异步的话,try ... catch 是处理不了的。
sex下面具体看一下 domain 模块的各个方法this
Domain.create()
创建一个 Domain 对象 domain
domain.run(fn)
把要运行的代码加入到域内,可以多次加入。 一旦加入的代码有异常就会触发domain的error事件。
domain 的 error 事件
error事件是当加入domain的代码抛出异常时触发的事件。
domain.bind(callback)
返回的函数将是一个包装,提供的回调函数。当返回的函数被调用时,被抛出的任何错误,将被路由到域的错误事件。
看例子:
var fs = require("fs"); var Domain = require("domain"); var d = Domain.create(); function readFile(filename, cb) { fs.readFile(filename, 'utf8', d.bind(function(er, data) { return cb(er, data ? JSON.parse(data) : null); })); } d.on('error', function(er) { console.log("有错误这里处理!") }); readFile("abc.txt");
domain.intercept(callback)
这个方法和bind方法很类似,但是包装器会把第一个err参数去掉,当有错误时只是单独的触发domain error事件。看下面代码:
var fs = require("fs"); var Domain = require("domain"); var d = Domain.create(); function readFile(filename, cb) { // 这里没有er fs.readFile(filename, 'utf8', d.intercept(function(data) { return cb(data ? JSON.parse(data) : null); })); } d.on('error', function(er) { console.log("有错误这里处理!") }); readFile("abc.txt");
【说明】
domain 模块不只这些方法,但除了上述介绍的方法外,其他的方法并没什么用,而且作者本人也不推荐用,所以没有介绍。
查看操作系统信息
这一节很简单,通过这个os模块可以得到操作系统相关的一些信息。var os = require("os");得到模块。
os.tmpdir();
得到系统临时文件夹路径。
os.endianness();
得到CPU字节顺序,在Buffer一章介绍过字节有"BE"和"LE"两种顺序。
os.hostname()
得到主机名称。
os.type()
得到系统类型,比如windows7 得到的结果是 Windows_NT
os.platform()
得到系统平台名称,比如windows7 得到的结果是 win32
os.arch()
得到系统架构名称,比如windows7 得到的结果是 ia32
os.release()
得到系统版本
os.uptime()
得到系统从开机到现在的运行时间,以秒为单位。
os.totalmem()
this得到内存总大小book
os.freemem()
得到系统可用内存大小
os.cpus()
得到CPU的信息
os.networkInterfaces()
得到全部网络接口信息。
os.EOL
得到系统的行结束标记。
单元测试
通过 var assert = require("assert") 得到断言模块。
下面讲解assert的各个测试方法。
assert(value, message)
assert.ok(value, [message])
上面两个方法相同,value如果为真值不会抛出异常,否则会抛出异常,message是错误信息。
assert.equal(actual, expected, [message])
断言 actual与expected相等。
assert.notEqual(actual, expected, [message])
断言 actual和expected不相等。
assert.deepEqual(actual, expected, [message])
断言 actual和expected相等(深度测试)。
assert.notDeepEqual(actual, expected, [message])
断言 actual和expected不相等(深度测试)。
assert.strictEqual(actual, expected, [message])
严格测试actual和expected相等。 相当于 ===
assert.notStrictEqual(actual, expected, [message])
严格测试actual和expected不相等。相当于 !==
assert.throws(block, [error], [message])
断言 block 函数会抛出异常。
assert.throws( function() { throw new Error("Wrong value"); }, function(err) { if ( (err instanceof Error) && /value/.test(err) ) { return true; } }, "unexpected error" );
assert.doesNotThrow(block, [message])
断言 block 函数不会抛出异常。
assert.ifError(value)
断言 value是个Error对象。
路径操作
这里的路径含义比较广,包括url,文件系统路径等,下面分别进行讲解。
path模块
这个模块是对文件系统的路径进行转换,它不会直接牵扯到文件系统,而仅仅是对路径字符串进行转换。
path.normalize(p)
路径规范化,说也没用,还是例子最实在。
var path = require("path"); console.log( path.normalize("c:\\windows\\system32\\..")) console.log( path.normalize("c:\\windows\\system32\\..\\..")) console.log( path.normalize("/user/home/brighthas/../leo"))
打印结果
c:\windows c:\ \user\home\leo
path.join([path1], [path2], [...])
连接路径,看例子:
var path = require("path"); console.log(path.join("c:","windows")); console.log(path.join("c:","windows",".."));
god打印结果good
c:\windows c:\
path.resolve([from ...], to)
相当于系统的cd命令,看例子:
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/wwwroot/static_files/gif/image.gif'
path.relative(from, to)
返回相对路径
path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb') // 返回 '..\\..\\impl\\bbb' path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb') // 返回 '../../impl/bbb'
path.dirname(p)
返回目录
path.dirname('/foo/bar/baz/asdf/quux') // 返回 '/foo/bar/baz/asdf'
path.basename(p, [ext])
返回路径的最后部分
path.basename('/foo/bar/baz/asdf/quux.html') // 返回 'quux.html' path.basename('/foo/bar/baz/asdf/quux.html', '.html') // 返回 'quux'
path.extname(p)
返回扩展名
path.extname('index.html') // 返回 '.html' path.extname('index.') // 返回 '.' path.extname('index') // 返回 ''
path.sep
特定系统的文件分割符,windows下是 “\” linux下是 “/” 。
path.delimiter
特定系统的路径分割符,windows下是 “;” 而linux下是 “:” 。
URL模块
模块可以对url字符串进行解析和转换。
下面通过具体例子,来掌握url模块的使用方式。
var url = require('url'); var o = url.parse("http://user:pass@host.com:8080/p/a/t/h?query=string#hash") console.log(o);
url.parse把url字符串转换成json对象,会打印出:
{ protocol: 'http:', slashes: true, auth: 'user:pass', host: 'host.com:8080', port: '8080', hostname: 'host.com', hash: '#hash', search: '?query=string', query: 'query=string', pathname: '/p/a/t/h', path: '/p/a/t/h?query=string', href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' }
下面把上述的json对象转换为url字符串形式,通过url.format方法
url.format({ protocol: 'http:', slashes: true, auth: 'user:pass', host: 'host.com:8080', port: '8080', hostname: 'host.com', hash: '#hash', search: '?query=string', query: 'query=string', pathname: '/p/a/t/h', path: '/p/a/t/h?query=string', href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' })
得到如下结果:
http://user:pass@host.com:8080/p/a/t/h?query=string#hash
通过url.resolve功能类似于path.resolve功能,参看官方给的例子。
url.resolve('/one/two/three', 'four') // '/one/two/four' url.resolve('http://example.com/', '/one') // 'http://example.com/one' url.resolve('http://example.com/one', '/two') // 'http://example.com/two'
querystring模块
querystring模块能处理url的查询部分。
querystring.stringify(obj,[sep],[eq])
obj参数是要转换的对象,sep[可选参数]表示分割器,默认&。 eq[可选]分配符,默认= 。 看下面官方例子。
querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' }) // 返回 'foo=bar&baz=qux&baz=quux&corge=' querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':') // 返回 'foo:bar;baz:qux'
querystring.parse(str, [sep], [eq])
这个方法与querystring.stringify正好相反,是把查询字符串形式转换为json形式。看官方例子:
querystring.parse('foo=bar&baz=qux&baz=quux&corge') // 返回 { foo: 'bar', baz: ['qux', 'quux'], corge: '' }