Bluebird.each Break If Solved
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 o
Solution 1:
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.
Here's how this works:
- Use Bluebird's
Promise.promisifyAll()
to automatically make promise returning methods for thePlayer
object so we can then use those in our control flow. - Use Bluebird's
Promise.mapSeries()
to iterate the array serially one at a time. - Chain the
Player.countAsync()
andPlayer.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. - 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). - 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.
The code:
// Promisify the Player object so the methods// this would usually be done wherever this module is loadedPlayer = Promise.promisifyAll(Player);
// create a special subclass of Error for our short circuitPlayerUpdateDoneextendsError {
constructor(name) {
super();
this.name = name;
}
}
// put logic into a function to make it cleaner to usefunctionaddToBuddyList(replicaArr) {
returnPromise.mapSeries(replicaArr, function(replicaname) {
returnPlayer.countAsync({buddyList: replicaname}).then(function(result) {
// if room left in buddy listif (result < 990) {
returnPlayer.updateAsync({'_id': buddyObj.buddyId}, {'buddyList': replicaname}).then(function() {
ReplicaList[replicaname].send(buddyObj);
// throw special exception to abort .mapSeries()// and stop further processingthrownewPlayerUpdateDone(replicaname);
});
}
});
}).then(function() {
// if it gets here, there were no players with rooms so just return nullreturnnull;
}).catch(function(result) {
// we used a special rejection as a shortcut to stop the mapSeries from executing// the rest of the seriesif (result instanceofPlayerUpdateDone) {
// change this special rejection into a resultreturn result.name;
}
// must have been regular error so let that propagatethrow result;
});
}
// sample usageaddToBuddyList(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 hereconsole.log(err);
});
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 rejectionPromise.firstToPassInSequence = function(arr, fn) {
let index = 0;
functionnext() {
if (index < arr.length) {
returnPromise.resolve().then(function() {
// if fn() throws, this will turn into a rejection// if fn does not return a promise, it is wrapped into a promisereturnPromise.resolve(fn(arr[index++])).then(function(val) {
return val ? val : next();
});
});
}
// make sure we always return a promise, even if array is emptyreturnPromise.resolve(null);
}
returnnext();
};
Promise.firstToPassInSequence(replicaArr, function(replicaname) {
returnPlayer.countAsync({buddyList: replicaname}).then(function(result) {
// if room left in buddy listif (result < 990) {
returnPlayer.updateAsync({'_id': buddyObj.buddyId}, {'buddyList': replicaname}).then(function() {
ReplicaList[replicaname].send(buddyObj);
return replicaname;
});
}
});
});
Post a Comment for "Bluebird.each Break If Solved"