关于异步执行的求助!
发布于 8个月前 作者 hsh075623201 625 次浏览

格式如下: async.each(role,function(name, cb){ redisClient.get(name,function(err,roleReply){ 。。。。 }) });

async.each(dept,function(name, cb){ redisClient.get(name,function(err,deptReply){ 。。。。。 }) });

分别存在role 以及dept的数组 现根据async,循环从redis中取数据,如何实现这两个函数并行执行,而且知道他们已经执行完成??

15 回复

如果你用 Promise:

Promise.all([
  roles.map(redis.getAsync.bind(redis)),
  depts.map(redis.getAsync.bind(redis))
])
  .then(function(result) {
    // results[0]   ==> roles
    // results[1]   ==> depts
  })

.getAsync 是 bluebird 给 redis client 自动封装的返回 promise 的函数。

function roll (nums, f) {
    var count = nums;
    return function () {
        count--;
        if (count === 0) {
            f.call(null);
        }
    };
}

var test = function () { console.log('ok.') };
var rollInstance = roll(2, test);

async.each(role,function(name, cb){
    redisClient.get(name,function(err,roleReply){
        。。。。
        rollInstance();
    });
});
async.each(dept,function(name, cb){
    redisClient.get(name,function(err,deptReply){
        。。。。。
        rollInstance();
    });
});

能不能不通过计数的方式实现啊 ?

由于是初学者,能否再 说的仔细点呢??

async.parallelasync.map 可以帮上忙。 试试下面的代码,没有环境未测试,大概是这个意思。

async.parallel([
    function(callback) { // task#1
        async.map(role, function(name, cb) {
            redisClient.get(name,function(err,roleReply){
                 cb(err, roleReply);
            });
        }, function(err, roles) {
                callback(err, roles);     
        });
    },
    function(callback){  // your second task
       
    }
],
function(err, results){
   // go and play with results
   
});

@hsh075623201 做梦吧!你要是学过C语言,就知道,最终都要计数,计算机才能识别。 你用的框架,内部也不过是计数而已。
JS解释到C,C对字符数组都要用末尾‘\0’和指定长度来确认字符串结束。

@GuoZhang 请问如下代码有问题嘛 ?我现在采用了如下方法,但不确定是否可以 由于都是数组,因此我先将数组合并了。。 var getValuesByKey = { getValue:function(key,callback){ var retVal=[]; redisClient.get(key,function(err,roleReply){ for(var i=0;i<JSON.parse(roleReply).component.length;i++){ … retVal.push(); } callback(null, retVal); }) } }

async.map(redisKey, getValuesByKey.getValue.bind(getValuesByKey), function(err, result){ … });

@hsh075623201 感觉没有问题,你实际使用一下吧。

getValuesByKey.getValue.bind(getValuesByKey)在你的情况下似乎没有必要,因为不存在getValue()没有使用this,可以简单地试着写成:

function getValue(key,  callback) {
        ....
}

async.map(redisKey, getValue, function (err, result) {
   ...
});

或直接匿名:

async.map(redisKey, function(key, callback) {
        ...
}, function (err, result) {
   ...
});


嗯 好的 谢谢!

@GuoZhang 你好 再次咨询下 代码如下: async.map(MenuPages, function(menuPage, callback) { … menuPage.save(); callback(null); }, function (err, result) { res.json(“success”); }); 我想要完成的是 将menuPages存入数据库 ,然后 返回success 但是上述方法返回后 有时候数据只存入一些,没有全部存入,应该怎么解决呢? 使用mongoose提供的create方法也出现这个问题 ,如下所示: Menu.create(MenuPages,function(err, result){ res.json(“success”); });

@hsh075623201 从你给出来的代码,不太能看到错误。

    menuPage.save();  // 同步的还是异步的?感觉应该是异步
    callback(null);          // 如果是的话,callback可能会在menuPage保存完成前调用

另外: 将menuPages存入数据库 ,然后 返回success – 在这种情况下,你似乎不需要每个menuPage保存后的返回值,因此,可以不使用async.map而是使用async.each

简单写了个例子:

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;
var async = require('async');

mongoose.connect('mongodb://localhost:27017/test');

// define model
var User = mongoose.model('User', new Schema({
                                    name: String
                                  }));

// create users
var users = [];
for (var i = 0; i < 5; ++i) {
  users.push({ name: 'user#' + i });
}

// and save them
async.each(users, function (user, callback) {
  User.create(user, function (err, user) {
    callback(err);
  });
}, function (err) {
  if (err) {
    console.log('Error: ' + err);
  } else {
    console.log('Done');
  }

  // disconnect if you intend to
  // mongoose.disconnect();
});

执行后查看数据库:

> db.users.find().pretty();
{
    "name" : "user#0",
    "_id" : ObjectId("53a1ad5d400b2aa6044c7afd"),
    "__v" : 0
}
{
    "name" : "user#2",
    "_id" : ObjectId("53a1ad5d400b2aa6044c7aff"),
    "__v" : 0
}
{
    "name" : "user#1",
    "_id" : ObjectId("53a1ad5d400b2aa6044c7afe"),
    "__v" : 0
}
{
    "name" : "user#3",
    "_id" : ObjectId("53a1ad5d400b2aa6044c7b00"),
    "__v" : 0
}
{
    "name" : "user#4",
    "_id" : ObjectId("53a1ad5d400b2aa6044c7b01"),
    "__v" : 0
}

@GuoZhang 你好,我还有些疑问,感觉你贴出来的代码 和我的思路差不多 ,你这段代码不是也将一个个数据保存至数据库,导致还没保存完 就调用callback,是我理解错了吗?

@hsh075623201

导致还没保存完 就调用callback

User.create(user, function (err, user) {
    callback(err);   // 这个callback是对保存数组中的每一项的回调 -- 这里就是这个user的处理是否成功还是有错误
                     // 而不是针对这个数组中的所有元素是否处理完成的
});

所有元素处理完毕的回调在这里:

 function (err) {  // 所有元素处理完毕了(也不见得一定是处理了所有元素)
  if (err) {            // 如果处理某个元素时错误(callback(err) 时,这个err不为空),会立马跳到这里
                        // 并且这里的err就是callback(err)时的那个err 
    console.log('Error: ' + err);
  } else {   // 如果执行到了这里,表示数组中的所有元素已经成功地处理完毕
    console.log('Done');
  }

附上async.each的源码,你体会一下:


    async.each = function (arr, iterator, callback) {
        callback = callback || function () {};    
        if (!arr.length) {   // 如果给的不是array-like参数
            return callback();  // 直接回调,做不下去了
        }
        var completed = 0;       // 计数,有多少个元素被成功处理了
        _each(arr, function (x) {       // 遍历arr中的所有元素 (_each只是利用了Array.prototype.forEach
                                        //  或自己for循环遍历(如果Array.prototype.forEach不存在))
            iterator(x, only_once(done) );  // 调用你的迭代函数处理数组中的每一个元素, 这个调用决定了
                                            // 1) 你的迭代函数的第一个参数是数组中的某元素
                                            // 2) 你的迭代函数的第二个参数是一个函数(值为only_once(done))
                                            //      only_once保证了你只能调用这个函数至多一次。根据函数done的实现,你必须
                                            //      在你的迭代函数中调用他一次,无论成功还是失败,否则计数completed在没有错误的情况
                                            //      下不会+1, 导致最终的callback不能执行 -- 具体看done函数
        });
        function done(err) {
          if (err) {   // 如果有错,立马回调 -- 报错
              callback(err);
              callback = function () {};  // 保证callback也只能被执行一次(想象如果有多个错误同时回调的情况)
          }
          else {
              completed += 1;         // 没错,计数+1
              if (completed >= arr.length) {  // 如果所有的处理都没有错
                  callback();     // 回调,处理完毕且无错误
              }
          }
        }
    };

@GuoZhang 你好 上面的那个问题 我都过create 方法搞定了 mongoose api [Model.create(doc(s), [fn])], 但是关于异步的疑问仍在 。。。我使用如下方法查询数据,并将有用的数据 返回 ,出现问题 1.返回的有时候 有值 ,有时候没有值 2.不管返回的有值 还是无值 ,打印的地方都没值 。。。 async.map(redisKey, function(key,callback){ var retVal=[]; redisClient.get(key,function(err,roleReply){ for(var i=0;i<JSON.parse(roleReply).menu.length;i++){ for(var j=0;j<docs.length;j++){ … retVal.push(docs[j]); } } callback(null, retVal); }) }, function(err, result){ if(err){ … }else{ var resultArray =[]; for(var i=0;i<result.length;i++){ resultArray = resultArray.concat(result[i]); } console.error("menu list:"+JSON.stringify(resultArray)); //不管 返回的是有值 还是 无值 这里打印的只有 "[]" res.json(resultArray); }

});

@GuoZhang 我可能找到原因了 我先自己看看 ,非常感谢你的耐心指导!

回到顶部