Nodejs async的concatSeries循环里面,嵌套回调函数同步问题【已解决,感谢jiangmiao同学】
Nodejs async的concatSeries循环里面,嵌套回调函数同步问题【已解决,感谢jiangmiao同学】
handler.myTasklist = function(msg,session,next){
var uid = session.uid;
taskDao.myTasklist(uid,function(err,res){
//res为一个数组,这里使用async的concatSeries方法,同步依次执行
async.concatSeries(res,function(task,callback){
var taskinfo;
//这里出现问题,直接跳过了taskDao,直接进入callback(null,data[taskinfo])了,正确的方法该怎样写呢?
taskDao.taskAttribute(task.id,function(err,res){
var attributes = []
for(var j=0;j<res.length;j++){
var attribute = {
title:res[j].title,
attributevalue:res[j].attributevalue
};
attributes.push(attribute);
}
taskinfo = {
title:task.title,
type:task.type,
status:task.status,
attributes:attributes
};
});
//将得到的taskinfo传入回调函数,由于没有同步taskDao.taskAttribute,直接导致这里到taskinfo为空
callback(null,data[taskinfo]);
},function(err,values){
console.log(“tasks:”+values);
next(null,{
route: ‘onMytasklist’,
tasks:values
});
});
});
};
要求就是:for循环里面 先执行taskDao.taskAttribute,取得taskinfo后 再执行下面的callback(null,data[taskinfo]);这个回调
希望不要嫌弃新人技术哈
【已解决,改变一下callback位置即可】
Nodejs async的concatSeries循环里面,嵌套回调函数同步问题【已解决,感谢jiangmiao同学】
在处理异步操作时,特别是涉及到数据库查询或者网络请求时,经常会遇到回调函数嵌套的问题。在你的例子中,你使用了async.concatSeries
来依次执行一系列任务,并且每个任务都涉及到了异步数据库查询。你需要确保在每次查询完成后,再继续执行后续的回调函数。
原始代码中的问题
原始代码中的问题是,在调用taskDao.taskAttribute
之后,直接执行了callback(null, data[taskinfo])
,而没有等待taskDao.taskAttribute
完成。这会导致taskinfo
为空,因为异步操作还没有完成。
解决方案
解决方案是将callback(null, taskinfo)
放在taskDao.taskAttribute
的回调函数内部,以确保在查询完成后再执行回调。
handler.myTasklist = function (msg, session, next) {
var uid = session.uid;
taskDao.myTasklist(uid, function (err, res) {
// 使用async的concatSeries方法,同步依次执行
async.concatSeries(res, function (task, callback) {
var taskinfo;
// 调用异步方法获取task信息
taskDao.taskAttribute(task.id, function (err, res) {
if (err) {
return callback(err); // 如果有错误,直接传递给回调
}
var attributes = [];
for (var j = 0; j < res.length; j++) {
var attribute = {
title: res[j].title,
attributevalue: res[j].attributevalue
};
attributes.push(attribute);
}
taskinfo = {
title: task.title,
type: task.type,
status: task.status,
attributes: attributes
};
// 将taskinfo传递给回调函数
callback(null, taskinfo);
});
}, function (err, values) {
if (err) {
console.error("Error:", err);
return next(err);
}
console.log("tasks:", values);
next(null, {
route: 'onMytasklist',
tasks: values
});
});
});
};
解释
- 异步操作:
taskDao.taskAttribute
是一个异步操作,它需要一段时间才能返回结果。 - 回调函数:在
taskDao.taskAttribute
的回调函数内部,我们构建了taskinfo
并将其传递给外部的callback
函数。 - 错误处理:如果在
taskDao.taskAttribute
中发生错误,我们可以直接通过callback(err)
传递错误。 - 最终回调:
async.concatSeries
的最终回调函数会在所有任务完成后被调用,并将所有taskinfo
组合成一个数组传递给next
。
通过这种方式,你可以确保每个异步操作都按顺序完成,从而避免了回调地狱(callback hell)的问题。
所有的循环都可以改写其异步形式,如for循环
function foo(items)
{
for (var i=0; i<items.length; ++i)
{
something();
}
another();
}
的异步版本则是
function foo(items, cb)
{
var i, once, next, done;
i = 0;
once = function() {
if (i >= items.length)
return done();
item = items[i];
process.nextTick(function() {
something();
next();
});
};
next = function() {
++i;
once();
};
done = function() {
another();
cb();
};
return once();
}
如果条件简单,也可合并写成
function foo(items, cb)
{
var i, once;
i = -1;
once = function() {
if (++i >= items.length) {
another();
return cb();
}
item = items[i];
process.nextTick(function() {
something();
once();
});
};
once();
}
不好意思,我是需要同步
就是for循环里面,先执行嵌套的taskDao.taskAttribute这个回调函数,然后再执行callback
现在的问题是,直接跳过了嵌套的taskDao.taskAttribute这个回调函数
要求就是:for循环里面 先执行taskDao.taskAttribute,取得taskinfo后 再执行callback这个回调
很好很强大,如果循环中要并发而不是顺序执行不知是否支持。
可以参考 IcedCoffeeScript的话await for为并发,for … await 则为顺序。
比如
await for i in [0..2]
# 并发
((i, cb) ->
# 顺序执行
for j in [0..2]
await setTimeout defer(), 500
console.log "#{i} #{j}"
cb()
)(i, defer())
console.log 'done'
输出为
# 3并发
0 0
1 0
2 0
# 等待 500 ms
0 1
1 1
2 1
# 等待 500 ms
0 2
1 2
2 2
done
在你的原始代码中,callback(null, data[taskinfo])
这一行被执行得太早了。因为在 taskDao.taskAttribute
的回调函数内部(即异步操作完成之后)之前,taskinfo
还没有被正确地赋值,所以你需要将 callback
放置在 taskDao.taskAttribute
的回调函数内部。这样可以确保 taskinfo
在被传递给 callback
之前已经被正确赋值。
以下是修正后的代码示例:
handler.myTasklist = function (msg, session, next) {
var uid = session.uid;
taskDao.myTasklist(uid, function (err, res) {
if (err) {
return next(err);
}
async.concatSeries(res, function (task, callback) {
taskDao.taskAttribute(task.id, function (err, res) {
if (err) {
return callback(err);
}
var attributes = [];
for (var j = 0; j < res.length; j++) {
var attribute = {
title: res[j].title,
attributevalue: res[j].attributevalue
};
attributes.push(attribute);
}
var taskinfo = {
title: task.title,
type: task.type,
status: task.status,
attributes: attributes
};
// 将 taskinfo 传递给 callback
callback(null, taskinfo);
});
}, function (err, values) {
if (err) {
return next(err);
}
console.log("tasks:" + values);
next(null, {
route: 'onMytasklist',
tasks: values
});
});
});
};
在这个修正后的版本中,callback(null, taskinfo)
被放置在 taskDao.taskAttribute
的回调函数内部。这确保了 taskinfo
在被传递给 async.concatSeries
的 callback
函数之前已经被正确赋值。