由于nodejs异步的工作机制,所以经常会用到回调函数
可以看到第2个请求只有start 没有end ,难道是第二个请求没有响应,但回到浏览器可以发现,三个分页均正常
但初学nodejs也很容易错误的使用回调
最常见的就是没有异步的回调
function foo(data,callback){
console.log(data);
if(data=='data'){//如果参数等于data则回传0
console.log("do something");
callback(0);
}else{//否则则回传错误信息
callback('数据错误');
}
}
foo('data',function(err){
console.log(err);
});
这样做虽然达到了预期效果,但是其本质还是一个同步的方法,
如果不用回调的话,代码会更易读更易维护
function foo(data){
console.log(data);
if(data=='data'){//如果参数等于data则返回0
console.log("do something");
return 0;
}else{//否则则返回错误信息
return '数据错误';
}
}
var result=foo('data');
console.log(result);
如果do something是比较复杂的计算,需要异步处理的话,则可以像下面这样修改
function foo(data,callback){
process.nextTick(function(){
console.log(data);
if(data=='data'){//如果参数等于data则回传0
console.log("do something");
callback(0);
}else{//否则则回传错误信息
callback('数据错误');
}
});
}
foo('data',function(result){
console.log(result);
});
console.log('after foo ');
可以看到结果,after foo打印在最前面
do something异步处理
还有一个问题就是回调函数访问外部变量,看下面的示例
var http=require("http");
var redis=require("redis");
var client=redis.createClient();
var counter=0;
var server=http.createServer(function(req,res){
counter++;
console.log("第"+counter+"个请求 start ");
client.keys("*",function(err,reply){
console.log("第"+counter+"个请求 end ");
res.end("data");
});
}).listen(3000);
console.info("server startup at 3000");
server.on("error",function(err){
console.err(err);
});
上面代码主要做的就是,当请求进来的时候,给统计器counter++,然后再查一下redis,查完redis再向浏览器发送响应res
为了使查redis这个动作尽量耗时,我在redis中加入了10w条记录,即有10w个key,执行keys *命令大约需要6、7秒
打开浏览器,开三个分页,在地址栏输入http://localhost:3000/?r=1231 (三个分页的r参数要不一样,可以避免浏览器使用缓存而不发送请求)
服务端,可以看到结果如下:
server startup at 3000
第1个请求 start
第1个请求 end
第2个请求 start
第3个请求 start
第3个请求 end
第3个请求 end
可以看到第2个请求只有start 没有end ,难道是第二个请求没有响应,但回到浏览器可以发现,三个分页均正常
而事实是第2个请求响应时,counter已经被修改成3了
这种需求在nodejs里是比较常见的
要解决也很简单,只需要使用闭包就行了
var counter=0;
var server=http.createServer(function(req,res){
counter++;
console.log("第"+counter+"个请求 start ");
client.keys("*",function(){
var c=counter;
return function(err,reply){
console.log("第"+c+"个请求 end ");
res.end("data");
}
}());
}).listen(3000);
把请求刚进来时的counter存在var c中,每个响应都有自己相对应的c了,就不会出错了
server startup at 3000
第1个请求 start
第2个请求 start
第1个请求 end
第2个请求 end
第3个请求 start
第3个请求 end