请问有没有异步改同步的库能处理类似ForEach的情况?
发布于 2年前 作者 shinka 1987 次浏览

这个情况比较恶心,比如forEach() 然后这个里面每个Item都执行一个异步调用的函数,比如请求数据库查询结果,我希望在forEach之后的代码块能在上面每个Item的异步函数执行完之后再执行,请问有没有这样的库或者其他替代方案?

也就是先解决forEach的异步问题改成同步,然后forEach里面每个item的异步问题也改成同步,然后再执行forEach后面的代码块。不知道有没有描述清楚,我用过async那个库,看似能解决问题但是尝试了一下不好用…

24 回复

不理解哪里不好用?敢问你会不会用?

Node异步查数据库是并发执行,效率高很多,为什么要同步啊? 你可以搞一个计数,全部item执行完了再触发后面的代码事件(函数)就可以啦。 不知道我理解有没有错。

额… 我照着官网的API写了一个 但是不好使…

@shinka 不好使说明你没写对啊!你上代码吧~我可以给你改改。

我以前用过的一段类似代码,因为即使中间某一条有错也要全执行完,所以err没有往回传。如果callback中err有值循环的最后那个function会立刻执行。这个根据你自己需要改。

    async.forEach(result, function(item,callback){
    var parms = packParms(item);
    api.inpatientPrescriptionPricing(parms,function(err,result) {
          if(err){
        console.error('inpatientPrescriptionPricing err:', parms);
        db.log(item.id,item.zyh,item.xmmc,err.msg);
        callback(null,result);
          }else{
        db.update(item, function (err,row) {
          if(err){
            console.error('update err: id = %d', item.id);
            callback(null,item);
          }else{
            callback(null,item);
          }
        });
          }
      });
    }, function(err,rs){
      if(err&&err.length>0){
        console.error('filterSeries err:',err);
        console.error('filterSeries rs:',rs);
    }
      process.exit(1);
  });

老赵的wind.js有异步改同步的功能,你查看下,我记得是有可以应用在for和forEach中的功能

@saighost 哦哦 谢谢啊 才上CNODE 公司出去秋游了 我会仔细研究一下你的代码的 非常感谢

好的 wind,js就听说了一下没看过 去看看他的forEach吧 谢啦

恩 看这个库了 可惜自己写了个例子失败了…

组长过来跟我讨论要改同步的问题 他也说到计数的方式了 但是觉得代码写得太丑不想那么做…

@saighost 这是我测试用的代码,我希望的效果是当forEach里面的异步函数都执行完毕后执行最后一个console.log,实际的结果是先执行完三个forEach,然后执行最下面那一行console.log,然后执行三个at的console,然后执行三个save的console。希望能在forEach,at,save都执行完事之后再执行最后的console.log

 var ids = ["50514054705efe0823000008", "505140e060b550402400000c", "505c092e54f35e414c000008"];
  async.forEach(ids, function(item){
    console.log("forEach and id:"+item);
    user.at(item, function(err, u){
      console.log("at and id:"+item);
      u.uid = "测试用";
      u.save(function(err, u2){
        console.log("save and id:"+item);
      });
    });
  });
  console.log("after async.forEach");

@shinka 你应该先理解什么是异步回调,补一下基础。

var ids = ["50514054705efe0823000008", "505140e060b550402400000c", "505c092e54f35e414c000008"];
async.forEach(ids, function(item){
  console.log("forEach and id:"+item);
  user.at(item, function(err, u){
    console.log("at and id:"+item);
    u.uid = "测试用";
    u.save(function(err, u2){
      console.log("save and id:"+item);
      callback(null);
    });
  });
},function(err,rs){
  console.log("after async.forEach");
});

@saighost 嗯 谢谢哈 昨天已经解决了 不过遇到一个新的问题 请问我用mongoose的话,想用where a_ids in aArray 或者 b_ids in bArray 或者c_ids in cArray,我刚用$where试了下失败了,代码如下,希望帮忙看看怎么整比较好。

var line = "";

if(uids_.length > 0){ line += "createby.uid in [" + uids_ + "]"; } if(gids_.length > 0){ line += " || createby.gid in [" + gids_ + "]"; } if(tids_.length > 0){ line += " || createby.tid in [" + tids_ + "]"; }

message.find({}).$where(line).setOptions(optionObj).exec(function(err, messages){ callback_(err, messages); });

@shinka mongoose没用过。。。你可以另开一个帖问问。

https://github.com/xinyu198736/queue_do 专门处理forEach列表里的异步转同步问题。

衍生项目(使用了queue_do的模块):

同步遍历文件夹:https://github.com/xinyu198736/walk_do

自动依赖分析器:https://github.com/xinyu198736/dependparser

@saighost 老哥 我有个关于async的疑问 今天用你上面的例子试了一下,发现如下问题,先贴上代码

 async.forEach(msgs, function(msg, cb){
            async.parallel({
              group: function(callback){
                if(msg.createby.gid){
                  group.at(msg.createby.gid, function(err, g){
                    callback(err, g);
                  });
                }else{
                  callback(null);
                }
              },
              user: function(callback){
                if(msg.createby.uid){
                  user.at(msg.createby.uid, function(err, u){
                    callback(err, u);
                  });
                }else{
                  callback(null);
                }
              },
            }, function(err, r){
              if(r.group){
                msg["group"] = r.group;
              }
              if(r.user){
                msg["user"] = r.user;
              }
              cb(msg);
            });
          }, function(arg1, arg2, arg3, arg4, arg5){
            1;
          });
在对msgs这个数组forEach的时候,会每次调用回调,然后回调里面取得这条message的创建者以及所在群的对象信息添加到msg属性中。但是最后一个callback是在第一个item执行完之后就调用了,由cb(msg)这句调用了,然后forEach继续执行其他的item,最后那个回调就不再执行了。我以为最后一个回调是forEach所有元素都遍历结束后才调用的。请问如果用async这个模块的话,有没有解决方法。不用计数啥的。

@shinka cb的第一个参数应该是err,第二个是msg。所以改成cb(null,msg)就OK了,以后写的多了就习惯了。执行一次就不再执行了是因为forEach(arr, iterator, callback)在遍历的时候如果有一个报err的时候就会直接执行callback然后结束。我上面的代码为了执行全部所以,callback的第一个参数都是null然后用自己的log记录了一下,你可以根据自己情况(出错时是否继续执行)自行修改。 回调第一个参数是err好像是nodejs里约定俗称的,你自己写的代码最好也保持这种风格。

@saighost 嗯嗯 我一开始第一个参数也是err,后来发现不行就把err删了也没成功 复制代码的时候忘记恢复回去了 刚跟老大讨论了一下 决定用async的forEachSeries了 谢谢老哥的意见哈~

@shinka forEachSeries没并发,如果为了限制并发数量可以用forEachLimit。顺序的肯定慢。

@saighost 恩恩 我改用forEachSeries了 满足需求了 呼呼 一天居然就写了一个纠结的函数…

回到顶部