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位置即可】
所有的循环都可以改写其异步形式,如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这个回调
@yandaoyong 如果你执行的taskAttribute是异步,那么整个循环就是异步。
@yandaoyong 如果要让callback在异步taskAttribute后执行,callback肯定要存在于taskAttribute的回调函数中。解决方法参见我的回答。要让包含异步循环顺序执行必须用异步的方式写循环。
我循环用的是concatSeries,这个方法是同步挨个执行的
@jiangmiao 怎么改一下taskAttribute,让它和callback同步?
@yandaoyong 同步的话callback就不会执行在taskAttribute之前。
@yandaoyong 如果要让callback在异步taskAttribute后执行,callback肯定要存在于taskAttribute的回调函数中。
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
};
// 提进来!
callback(null,data[taskinfo]);
});
@yandaoyong 哪里是异步的终点写哪里,如果终点被隐藏,重写代码。
@yandaoyong 客气,我也没看仔细看问题,看到你另一个循环的贴子就回了个循环异步的变换,异步流程上的所有问题都可以用类似的方法拆解改写。
@jiangmiao 上次你说到循环改写异步的问题, 我来自卖自夸了. 楼主另一个帖子里 (话说那个帖子删了? 我只好贴这里来了见谅) 那段代码改写成 Stekinscript 异步管道形式如下 (# 号之后是注释, 对比原有的 js 代码)
import handler, taskDao
handler.myTasklist: (msg, session, next): # handler.myTasklist = function(msg,session,next){
uid: session.uid # var uid = session.uid;
taskDao.myTasklist(uid, (error, res): # taskDao.myTasklist(uid,function(err,res){
# var tasks = [];
tasks: res |: # for(var i=0;i<res.length;i++){
# var task = res[i];
# (function(tasks,task){
taskDao.taskAttribute($.id, %(err, res)) # taskDao.taskAttribute(task.id,function(err,res){
# var attributes = []
attributes: res |: { # for(var j=0;j<res.length;j++){
# var attribute = {
title: $.title, # title:res[j].title,
attributevalue: $.attributevalue, # attributevalue:res[j].attributevalue
# };
# attributes.push(attribute);
} # }
$result.push({ # var taskinfo = {
title: $.title, # title:task.title,
type: $.title, # type:task.type,
status: $.status, # status:task.status,
attributes: attributes, # attributes:attributes
# };
# tasks.push(taskinfo);
}) # });
# })(tasks,task);
# }
next(null, { # next(null,{
route: 'onMytasklist', # route: 'onMytasklist',
tasks: tasks, # tasks: tasks
}) # });
) # });
上面那段代码 # };
用 Stekinscript 最新分支编译, 产生等价于 (之所以说等价于, 是删去一些无用语句并且进行代码格式化之后的结果) 下面的 js 代码, 将管道也就是循环中的异步改写成递归, 并且将之后的语句 (next
调用, 因为 stekinscript 会作一些 name mangle 因此生成的代码中叫做 $c_next
) 放在递归的末尾执行
(function () {
handler.myTasklist = (function ($c_msg, $c_session, $c_next) {
var $c_uid;
$c_uid = $c_session.uid;
taskDao.myTasklist($c_uid, (function ($c_error, $c_resA) {
var $c_tasks;
(function ($list) {
if (!($list) || $list.length === undefined) throw 'not iterable';
function $next($index, $result) {
if ($index === $list.length) {
$c_tasks = $result;
$c_next(null, ({
"route": "onMytasklist",
"tasks": $c_tasks
}));
}
else {
var $element = $list[$index];
var $c_attributes, $c_err, $c_res;
taskDao.taskAttribute($element.id, (function ($tp_err, $tp_res) {
$c_err = $tp_err;
$c_res = $tp_res;
$c_attributes = (function ($list) {
if (!($list)) return;
var $result = [];
var $ind = 0;
var $next = function () {};
var $pipeRet;
for (var $k in $list) {
if ($ind === $list.length) {
break;
}
$pipeRet = (function ($index, $key, $element) {
$result.push(({
"title": $element.title,
"attributevalue": $element.attributevalue
}));
return [0];
})($ind, $k, $list[$k]);
switch ($pipeRet[0]) {
case 1:
return $pipeRet[1];
}++$ind;
}
return $result;
})($c_res);
$result.push(({
"title": $element.title,
"type": $element.title,
"status": $element.status,
"attributes": $c_attributes
}));
return $next($index + 1, $result);
}));
}
}
$next(0, []);
})($c_resA);
}));
});
})();
请多指教.
很好很强大,如果循环中要并发而不是顺序执行不知是否支持。
可以参考 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
@jiangmiao 惭愧, 还没这种支持. 很有意思的样子, 得看看生成的 js 代码是怎么布置的.