2017-01-21 16 views
0

条件が満たされてから残りの部分をスキップするまで配列の各要素をテストしたい。これは私が思いついたコードです、それは働いているようですが、私は実際に安全か予期しない副作用があるか分かりません。他の解決策が歓迎される。Bluebird.eachが解決したらブレークする

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; 
      } 
     }); 
     } 
    }); 
    } 
}); 
+1

// 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); }); 

最初の約束はtruthy値に解決するときに停止独自のシーケンサーを作るほうが簡単かもしれません。 count() 'と' Player.update() 'は非同期操作ですが、これは正しく動作しません。 '.each()'へのコールバックは、コールバックの非同期操作を表す約束を返す必要があります。あなたが持っている方法では、コールバックコードの外側から、いつ完了したかを知る方法はありません。また、Bluebirdを使用しているので、 'Promise.any()'を使用して、必要な方法を解決する最初の値を取得できます。 – jfriend00

+0

より良い方法を提供するには、達成しようとしていること、厳密なシリアル順で配列を処理するかどうか、複数のプレーヤーを並行して処理できるかどうか、あなたが達成しようとしている正確な結果。 – jfriend00

+0

@ jfriend00利用可能なボットの配列を調べ、それらのどれが友人リストに残っているかを確認する必要があります。 Model.countを使用して、リストにある現在の友人数を取得します。理想的には、配列内にある順序でチェックするのが理想的です。空のスロットを持つボットが見つかったら、ボット名をデータベースに保存します。その操作が成功すると、約束が解決され、他のすべての反復/要素はスキップされます。 – Trax

答えて

1

、あなたがリストを更新して起こるすべてのエラーをバックに通信することができます自分のバディリスト内の部屋を持つプレイヤーを見つけたときにシリアルに一つずつ選手を列挙し、反復を中止しようとしている場合は、次に、それを行うための1つの方法があります。これがどのように動作するか

はここにあります:私たちは、その後私たちの制御フローのものを使用できるように

  1. 使用ブルーバードのPromise.promisifyAll()が自動的Playerオブジェクトのための約束を返すメソッドを作成します。
  2. BluebirdのPromise.mapSeries()を使用して、アレイを一度に1つずつ連続して反復処理します。
  3. Player.countAsync()Player.updateAsync()のメソッドが正しくシーケンスされ、.mapSeries()から戻ってくるので、次の配列要素への繰り返しを続ける前に完了するのを待ちます。
  4. 部屋のあるプレイヤーを見つけ、バディリストを正常に更新したら、特別に例外をスローします。これは現在の約束を拒否し、.mapSeries()に反復を停止させます(あなたが望んだ通りです)。
  5. .catch()を上位レベルに追加すると、特別な拒否がテストされ、成功した解決済みの約束に変わります。他のエラーの場合は、引き続き実際のエラーとして伝播させてください。

コード: `プレイヤーを想定すると

// 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; 
      }); 
     } 
    }); 
}); 
+0

あなたの2番目の提案に行って、ありがとう、 – Trax

関連する問題