nodejs正确使用回调函数

时间:2021-06-20 05:35:05

由于nodejs异步的工作机制,所以经常会用到回调函数

但初学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