Bluebird.each中断,如果解决了 [英] Bluebird.each break if solved

查看:80
本文介绍了Bluebird.each中断,如果解决了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试数组的每个元素,直到满足条件,然后跳过其余的部分.这是我想出的代码,它似乎可以正常工作,但是我不确定它是否真正安全或有意想不到的副作用.欢迎其他解决方案.

I want to test each element of an array until a condition is met then skip the rest. This is the code I came up with, it seems to be working but I'm not sure if its actually safe or it has unexpected side effects. Other solutions are welcomed.

let buddyAdded = false;
replicaArr = _.keys(ReplicaList);
Promise.each(replicaArr, function(replicaname) {
  if (!buddyAdded) {
    Player.count({
      'buddyList': replicaname
    }, function(err, result) {
      if (err) {

      } else if (result < 990) {

        Player.update({
          '_id': buddyObj.buddyId
        }, {
          'buddyList': replicaname
        }, function(err) {
          if (err) {

          } else {
            ReplicaList[replicaname].send(buddyObj);
            buddyAdded = true;
            // success stop here and skip all the other  array elements
            return;
          }
        });
      }
    });
  }
});

推荐答案

如果您要一次枚举一个玩家,并在好友列表中找到有空间的玩家时中止迭代,则可以更新列出并传达发生的任何错误,那么这是一种解决方法.

If you're trying to enumerate the players serially one at a time and abort the iteration when you find a player with room in their buddy list that you can update the list and communicate back any errors that happen, then here's one way of doing it.

这是它的工作方式:

  1. 使用Bluebird的Promise.promisifyAll()Player对象自动做出承诺返回方法,以便我们可以在控制流中使用这些方法.
  2. 使用Bluebird的Promise.mapSeries()一次一次迭代数组.
  3. 绑定Player.countAsync()Player.updateAsync()方法,以便它们正确排序并从.mapSeries()返回它们,以便在继续迭代到下一个数组元素之前等待它们完成.
  4. 如果我们找到一个有空间的玩家并成功更新了其好友列表,则抛出一个特殊的异常.这将拒绝当前的Promise链,并导致.mapSeries()停止其迭代(这就是您想要的内容).
  5. 在更高级别添加.catch()来测试特殊拒绝,并将其转变为成功的已解决承诺.如果是其他错误,则让该错误继续作为实际错误传播.
  1. Use Bluebird's Promise.promisifyAll() to automatically make promise returning methods for the Player object so we can then use those in our control flow.
  2. Use Bluebird's Promise.mapSeries() to iterate the array serially one at a time.
  3. Chain the Player.countAsync() and Player.updateAsync() methods so they sequence properly and return them from .mapSeries() so it waits for them to complete before continuing the iteration to the next array element.
  4. If we find a player with room and successfully update its buddy list, then throw a specially exception. This will reject the current promise chain and cause .mapSeries() to stop it's iteration (which is what you said you wanted).
  5. Add a .catch() at the higher level that tests for the special rejection and turns it into a successful resolved promise. If it's some other error, then let that continue to propagate as an actual error.

代码:

// Promisify the Player object so the methods
// this would usually be done wherever this module is loaded
Player = Promise.promisifyAll(Player);

// create a special subclass of Error for our short circuit
PlayerUpdateDone extends Error {
    constructor(name) {
        super();
        this.name = name;
    }
}

// put logic into a function to make it cleaner to use
function addToBuddyList(replicaArr) {

    return Promise.mapSeries(replicaArr, function(replicaname) {
        return Player.countAsync({buddyList: replicaname}).then(function(result) {
            // if room left in buddy list
            if (result < 990) {
                return Player.updateAsync({'_id': buddyObj.buddyId}, {'buddyList': replicaname}).then(function() {
                    ReplicaList[replicaname].send(buddyObj);
                    // throw special exception to abort .mapSeries()
                    //    and stop further processing
                    throw new PlayerUpdateDone(replicaname);
                });
            }
        });
    }).then(function() {
        // if it gets here, there were no players with rooms so just return null
        return null;
    }).catch(function(result) {
        // we used a special rejection as a shortcut to stop the mapSeries from executing
        //    the rest of the series
        if (result instanceof PlayerUpdateDone) {
            // change this special rejection into a result
            return result.name;
        }
        // must have been regular error so let that propagate
        throw result;
    });
}

// sample usage
addToBuddyList(replicaArr).then(function(name) {
    if (name) {
        console.log(`Updated player ${name}`);
    } else {
        console.log("No players with room in their buddy list");
    }
}).catch(function(err) {
    // error here
    console.log(err);
});


使自己的音序器在第一个promise解析为真实值时停止运行可能更简单:


It may be simpler to make your own sequencer that stops when the first promise resolves to a truthy value:

// fn will be passed each array element in sequence
// fn should return a promise that when resolved with a truthy value will stop the iteration
//    and that value will be the resolved value of the promise that is returned from this function
// Any rejection will stop the iteration with a rejection
Promise.firstToPassInSequence = function(arr, fn) {
    let index = 0;

    function next() {
        if (index < arr.length) {
            return Promise.resolve().then(function() {
                // if fn() throws, this will turn into a rejection
                // if fn does not return a promise, it is wrapped into a promise
                return Promise.resolve(fn(arr[index++])).then(function(val) {
                    return val ? val : next();
                });
            });
        }
        // make sure we always return a promise, even if array is empty
        return Promise.resolve(null);
    }
    return next();
};


Promise.firstToPassInSequence(replicaArr, function(replicaname) {
    return Player.countAsync({buddyList: replicaname}).then(function(result) {
        // if room left in buddy list
        if (result < 990) {
            return Player.updateAsync({'_id': buddyObj.buddyId}, {'buddyList': replicaname}).then(function() {
                ReplicaList[replicaname].send(buddyObj);
                return replicaname;
            });
        }
    });
});

这篇关于Bluebird.each中断,如果解决了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆