2017-10-05 9 views
0

今日私は、再帰とネストされた約束を使用して約束を繰り返していたことを認識し、Q.all()を正しく使用する方法を学びたいと思いました。私は一連の非同期関数を反復して、それらのすべてが解決するのを待ってから続行しようとしています。この現在の実装では、約束が解決されるのを待たずに、Q.allが直ちに返されます。ここでは反復機能のための私のコードreturn q.all()は、deferred.resolveでラップされていない限り、解決を待っていません

var updateNewReleasePlaylists = function() { 
    var self = this; 
    var promises = []; 
    var deferred = Q.defer(); 

    // query for all users who have new releases 
    User.find({ 
      $and: [{ 
        'new_releases': { 
         $exists: true, 
         $ne: [] 
        } 
       }, 
       { 
        'refresh_token': { 
         $exists: true 
        } 
       } 
      ] 
     }, 'new_releases', 
     function (err, users) { 
      if (err) { 
       throw new Error(err); 
      } 
      for (var i = 0; i < users.length; i++) { 
       console.log('when?') 
       promises.push(updatePlaylist(users[i])); 
      } 
     }); 
return Q.all(promises); 

} 

、ここではそれが呼び出している非同期関数である:

function updatePlaylist(user) { 
    var deferred = Q.defer(); 
    User.findOne({'_id': user._id}, function(err, user) { 
     if (err) { 
      deferred.reject(err); 
     } 
     console.log(user); 
     deferred.resolve(); 
    }) 
    return deferred.promise; 
} 

私は次のように実装を変更した場合ので、それは完全に正常に動作します:

var updateNewReleasePlaylists = function() { 
    var self = this; 
    var promises = []; 
    var deferred = Q.defer(); 

    // query for all users who have new releases 
    User.find({ 
      $and: [{ 
        'new_releases': { 
         $exists: true, 
         $ne: [] 
        } 
       }, 
       { 
        'refresh_token': { 
         $exists: true 
        } 
       } 
      ] 
     }, 'new_releases', 
     function (err, users) { 
      if (err) { 
       throw new Error(err); 
      } 
      for (var i = 0; i < users.length; i++) { 
       console.log('when?') 
       promises.push(updatePlaylist(users[i])); 
      } 
      deferred.resolve(Q.all(promises)); // DIFFERENT 
     }); 
     return deferred.promise; // DIFFERENT 
} 

これは私の言うことではありませんが、これを実装する方法は間違っていますが、最初に正しく取りたいと思います。何か助けがあれば、ここで私がupdateNewReleasePlaylistsという関数をテスト用に呼び出しています。

it('updateNewReleasePlaylists should properly resolve after all users playlists have been updated', function (done) { 
     this.timeout(60000); 
     testHelper.stageSpotifyUser(20) 
      .then(testHelper.stageSpotifyUser(20)) 
      .then(testHelper.stageSpotifyUser(20)) 
      .then(function() { 
       playlist.updateNewReleasePlaylists() 
        .then(function (promises) { 
         console.log(promises.length); 
         console.log('should be after'); 
         done(); 
        }) 
      }) 
    }) 

おかげさまでありがとうございました。

+0

あなたは非同期的に( 'find'コールバックで)' promises'配列にプッシュしますが、 'Q.all'ではすぐにそれを使用します。もちろんそれはそこに空であり、すぐに成就する。あなたは 'User.find'を適切に約束し、' then'コールバックで配列と 'Q.all' * only *を使うべきです! – Bergi

答えて

1

約束配列が空の場合は、何も待たずに戻り値を得るのが正しいと思われます。関数(err、users)がまだ呼び出されていないため、find()が非同期な性質を持つため、promises配列はまだ空です。

したがって、私がfind()を非同期にすることが正しいのであれば、必要ならUser.find()またはpromise-wrap全体を返して返すべきです。

+0

うんUser.findは非同期です。したがって、この特定のユースケースでは、Q.allをdeferred.resolve()でラップすることは可能ですか?私がオンラインで見た例の多くはそうしていません。 – Ryan

+0

私は約束のラッピングに間違いはありません。それを行うライブラリがあります。私が助けてくれれば、私の答えに合格とマークしてください。チアーズ – JohnPan

関連する問題