其他工具模块

定时器

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: '' }