Node Cookbook(英文)读后感
by snoopyxdy
at 2012-09-04 09:08:38
original http://snoopyxdy.blog.163.com/blog/static/60117440201283112858425
执行的结果就是 done 永远不会被打印出来,因为node在同一时刻只能做一件事情,所以settimeout永远没有机会执行。所以我们在事件驱动的项目中尽量的使用无阻塞的I/O操作。EE = require('events').EventEmitter;
ee = new EE();
die = false;
ee.on('die', function() {
die = true;
});
setTimeout(function() {
ee.emit('die');
}, 100);
while(!die) {
}
console.log('done');
我们向一个不存在的域名发送了一条http的get请求,当然肯定会抛出异常,这时try和catch并没有能帮助我们捕获这个异常,因为http.get返回的不是一个error对象,而是http.ClientRequest对象。所以异步的错误不能用try和catch来捕获。var http = require('http')
var opts = {
host: 'sfnsdkfjdsnk.com',
port: 80,
path: '/'
}
try {
http.get(opts, function(res) {
console.log('Will this get called?')
})
}
catch (e) {
console.log('Will we catch an error?')
}
所以一旦我们在某一个监听器中throw了error,则接下来的监听器将不会再执行了,这个需要我们注意一下。EventEmitter.prototype.emit = function(type) {
...
var handler = this._events[type];
...
} else if (isArray(handler)) {
var args = Array.prototype.slice.call(arguments, 1);
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
return true;
...
};
核心代码就是上面的这段,利用pipe方法将2个stream的实例连接起来,这样一边从file读取文件一边就可以响应给客户端了。但是这样真能提升效率吗?我在本地的虚拟机做了一个小小的压力测试,输出一张5mb的单反照片,我们先看测试代码:var s = fs.createReadStream(filepath).once('open', function () {
response.writeHead(200, headers);
this.pipe(response);
}).once('error', function (e) {
console.log(e);
response.writeHead(500);
response.end('Server Error!');
});
B、利用streamvar http = require('http');
var fs = require('fs');
http.createServer(function (request, response) {
fs.readFile('./DSC_0004.JPG', function(err,data){
if(err){
console.log(e);
response.writeHead(500);
response.end('Server Error!');
return;
}
response.writeHead(200, {'Content-Type': 'image/jpeg'});
response.end(data);
})
}).listen(3000);
压测环境,虚拟机linux2.6.8,2cpu,256MB内存,测试工具ab,语句 ab -c 10 -n 50 http://192.168.11.66:3000/var http = require('http');
var fs = require('fs');
http.createServer(function (request, response) {
var s = fs.createReadStream('./DSC_0004.JPG').once('open', function () {
response.writeHead(200, {'Content-Type': 'image/jpeg'});
this.pipe(response);
}).once('error', function (e) {
console.log(e);
response.writeHead(500);
response.end('Server Error!');
});
}).listen(3000);
这样存在着一个漏洞,如果用户请求了/static/../app.js,我们的拼接后的路径就成了:/usr/local/node/app/static/../app.js,这样我们就把我们的启动文件app.js发送给了用户,用户可以通过这样的方法直接拿到我们项目的所有文件,而且如果我们用 root 权限启动node.js的话整个系统的文件恶意用户都可以看到了。var path = require('url').parse(request.url).pathname;
fs.readFile(__dirname+path, function (err, data) {
if (err) throw err;
response.end(data);
});
var buf;data.on('data', function(err, buffer){buf += buffer;})
以上代码利用buffer.copy获得word.txt文本内的数据,word.txt是一个大小为3.16MB的文件。执行1000次读取后所花时间为:var fs = require('fs');
var f = './word.txt';
function streamtread(end){var buf;
var s = fs.createReadStream(f).once('open', function () {
}).once('end', function(){if(!end) return console.timeEnd('streamtest');
streamtread(--end);
});
fs.stat(f, function(err, stats) {
var bufferOffset = 0;
buf = new Buffer(stats.size);
s.on('data', function (chunk) {
chunk.copy(buf, bufferOffset);
bufferOffset += chunk.length;
});
});
}
console.time('streamtest');
streamtread(1000);
streamtest: 90536msvar fs = require('fs');
var f = './word.txt';
function streamtread(end){
var buf='';
var s = fs.createReadStream(f).once('open', function () {
}).once('end', function(){
if(!end) return console.timeEnd('streamtest');
streamtread(--end);
});
fs.stat(f, function(err, stats) {
s.on('data', function (chunk) {
buf += chunk;
});
});
}
console.time('streamtest');
streamtread(1000);