2017-01-25 17 views
0

私は開発中のAngularJSアプリケーションで、複数のアップロードされたファイルを非同期的に処理して、SuiteCRMインスタンスに追加するルーチンを準備します。全体的に、コードはバグがありませんが、私は遅延呼び出しが次々に実行され、すべての約束が解決されるまで待っているスクリプトに結果を渡していないことを発見しています。おそらく誰かが、私が望む結果を得るために、これらをつなぐ方法を教えてくれるでしょうか?結果を使用したAngularJSでの複数の非同期呼び出し

function fileReader(file) { // perform async operation 
     var deferred = $q.defer(); 
     var reader = new FileReader(); 
     reader.onload = function() { 
      deferred.resolve(reader.result.replace(/^(.*),/g, "")); 
     }; 
     reader.readAsDataURL(file); 
     return deferred.promise; 
    } 

    $scope.uploadFiles = function() { 
     console.log('Starting uploads'); 
     $scope.uploadClicked = true; 
     $scope.uploadProgress = {}; 
     $applicationID = $('#application_id').val(); 
     var tmpMerchData = SessionService.getMerchantData(); 
     var isoID = SessionService.getISOID(); 
     if ($scope.fileList && $scope.fileList.length) { 
      var $myFiles = $scope.fileList; 
      for (var f = 0; f < $myFiles.length; f++) { 
       var thisFile = $myFiles[f]; 
       console.debug(thisFile); 
       fileReader(thisFile.file).then(function (result) { 
        ApplicationFactory.createNewUploadedDocument(thisFile, thisFile.templatetype, result, thisFile.description, $scope.userID, tmpMerchData.id, $applicationID, isoID).then(
          function successCallback(response) { 
           if (response.data.status === 1) { 
            console.log("Document creation succeeded"); 
            $scope.uploadProgress = { 
             'progress': 100, 
             'index': f 
            }; 
           } else { 
            console.log("Document creation failed"); 
           } 
          }, function errorCallback(response) { 
         console.debug("Error returned from createNewUploadedDocument", response); 
        }); 
       }); 
      } 
     } 
    }; 

だから、あなたが見る、私は私の$ scope.fileListにF(ファイル)ごとにcreateNewUploadedDocument関数にそれを渡すために、ファイルの内容を返し、ファイルを処理するためにFileReaderをする必要があります。 NGFの複数のファイルオプションは、これらのファイルのそれぞれに特定のテンプレートタイプと説明があるため、私には利用できません。

ご提供いただけるお手伝いがあれば、幸いです。

EDIT - 私はこのChaining multiple promises created through for loopと、このangular $q, How to chain multiple promises within and after a for-loopを読んだことがあるが、どちらも私の特定の状況のた​​めの任意の使用可能なフィードバックを提供しています。約束事は$ q.allを使って入れ子にして組み合わせることができますが、依然として結果データを互いに提供することはできますか? 私の内部メソッドは、REST APIの呼び出しです。何の違いもありませんが、呼び出すためにはFileReaderの約束の結果が必要です。

+0

動作しない部分は何ですか?コードはちょっと面倒ですが、うまくいくはずですが、あなたが望む結果が何であるかをはっきりと把握していないので、手助けするのは難しいです。 –

+0

これは、基本となる関数を呼び出す前に、すべてのfileReader約束をループします。 – DevlshOne

+0

それはできません。最初の約束事が 'fileReader'から解決されたとき、それは最初の' .then() 'に続かなければなりません。それを止めることは何もないので、 '.then()'のいずれかに入る前にすべての約束を待っている場合は、ちょうど非論理的です。 –

答えて

0

ANSWER - 元のコードのこの更新されたバージョンは、問題を修正します。

angular.forEachと、いくつかのクリーンアップされた変数名と再利用が実装されていることに注意してください。

$scope.uploadFiles = function() { 
     console.log('Starting uploads'); 
     $scope.uploadClicked = true; 
     $scope.uploadProgress = {}; 
     $applicationID = $('#application_id').val(); 
     var tmpMerchData = SessionService.getMerchantData(); 
     var isoID = SessionService.getISOID(); 
     if ($scope.fileList && $scope.fileList.length) { 
      angular.forEach($scope.fileList, function (thisFile, f) { 
       console.log('Starting upload #', f); 
       fileReader(thisFile.file).then(
         function (fileContents) { 
          ApplicationFactory.createNewUploadedDocument(thisFile, thisFile.templatetype, fileContents, thisFile.description, $scope.userID, tmpMerchData.id, $applicationID, isoID).then(
            function successCallBack(response) { 
             if (response.data.status === 1) { 
              console.log('Document creation succeeded'); 
              $scope.uploadProgress = { 
               'progress': 100, 
               'index': f 
              }; 
             } else { 
              console.log('Document creation failed'); 
             } 
            }, function errorCallback(response) { 
           console.debug('Error returned from createNewUploadedDocument ', response); 
          }); 
         }); 
      }); 
     } 
    }; 
+0

'f'はクロージャーに閉じ込められていますが、' $ scope.uploadProgress'はおそらく実際の進捗状況の信頼できない指標になります。 'ApplicationFactory.createNewUploadedDocument()'が非同期であるため、応答が元の順序に戻ってくるという保証はありません。体温計スタイルのインジケータの場合、100%以外の場所ではどこでもジャンプして終了することができます。 –

+1

したがって、 '' index ':f''の代わりに '' index':++ count'を使います。 'var count = 0'は' $ scope.fileList.forEach() 'の外側で宣言されています。これで、クロージャが必要なくなり、 'for'ループに戻ることができます。 –

+0

実際に、 '$ scope.uploadProgress'がアップロードの進行状況を示すものではないので、ファイルが終了するとすぐに100%にジャンプします。しかし、私はあなたが何を意味するかを見ます。 – DevlshOne

-1

$ qサービスを効果的に使用できます。 $ q.all()を使用すると、約束事の配列を渡します。結果として、各約束事の結果の配列が同じ順序で得られます。 だから我々はこのようにあなたのコードを書き換えることができます。

if ($scope.fileList && $scope.fileList.length) { 
    var $myFiles = $scope.fileList; 
    var promisesFileReader = []; 
    var promisesUploadedDocument = []; 
    for (var f = 0; f < $myFiles.length; f++) { 
     var thisFile = $myFiles[f]; 
     console.debug(thisFile); 
     promisesFileReader.push(fileReader(thisFile.file)); 
    } 

    $q.all(promisesFileReader) 
     .then(function(results) { 

     //We loop on results and push all the UploadDocument promises with the correct result 
     for (var i = 0; i < results.length; i++) { 
      promisesUploadedDocument.push(ApplicationFactory.createNewUploadedDocument(thisFile, thisFile.templatetype, results[i], thisFile.description, $scope.userID, tmpMerchData.id, $applicationID, isoID)); 
     } 

     $q.all(promisesUploadedDocument) 
      .then(
       function successCallback(response) { 
        if (response.data.status === 1) { 
        console.log("Document creation succeeded"); 
        $scope.uploadProgress = { 
         'progress': 100, 
         'index': f 
        }; 
        } else { 
        console.log("Document creation failed"); 
        } 
      }, 
       function errorCallback(response) { 
       console.debug("Error returned from createNewUploadedDocument", response); 
      }); 
     }); 
} 
+3

これは、 'for'ループの各繰り返しで' $ q.all'を呼び出すので動作しません。ループの外側で '$ q.all'を移動させ、' fileReader'からの約束事の全てを持っていれば、一度呼び出す必要があります。 –

+0

申し訳ありませんが、これは動作しません。それは "結果" f回目の回数を返します。増加する大きなオブジェクトとして毎回。 – DevlshOne

+0

すみません。あなたはforループから$ q.allの再取得を行う必要があります。ループはすべての約束を配列にプッシュすることを許し、その後、$ q.allで約束をすべて呼び出すことができます。 –

関連する問題