Angular $ q服务 - 限制Promise数组的并发性

时间:2015-08-31 01:09:03

标签: javascript angularjs asynchronous concurrency angular-promise

可能有助于为此问题提供一些背景上下文:我正在构建一个角度服务,以便于将多部分表单数据块(mp4视频)上传到云中的存储服务。

我试图限制同时发生的未解决的promise(PUT块数据请求)的数量。我正在使用$q.all(myArrayOfPromises).then()...来监听正在解析的所有块上传承诺,然后在发生这种情况时返回异步调用(POST来完成文件)。我认为我的算法遇到了竞争条件,因为$q.all()在所有作业被安排用于具有大量块的文件之前被调用,但是成功用于较小的文件。

这是我的算法。

var uploadInChunks = function (file) {
   var chunkPromises = [];
   var chunkSize = constants.CHUNK_SIZE_IN_BYTES;
   var maxConcurrentChunks = 8;
   var startIndex = 0, chunkIndex = 0;
   var endIndex = chunkSize;
   var totalChunks = Math.ceil(file.size / chunkSize);
   var activePromises = 0;

   var queueChunks = function () {
      while (activePromises <= maxConcurrentChunks && chunkIndex < totalChunks) {
         var deferred = $q.defer();
         chunkCancelers.push(deferred); // array with broader scope I can use to cancel uploads as they're happening

         var fileSlice = file.slice(startIndex, Math.min(endIndex, file.size));

         chunkPromises.push(addChunkWithRetry(webUpload, chunkIndex, fileSlice).then(function () {
           activePromises--;
           queueChunks();
        });

        activePromises++;
        startIndex += chunkSize;
        endIndex += chunkSize;
        chunkIndex++;
     }
  }

  queueChunks();

  return $q.all(chunkPromises).then(function () {
     return filesApi.completeFile(file.fileId);
  });
};

即使过早调用$q.all,最终仍会执行并成功解析仍在等待/甚至未安排的文件块。

我已经完成了关于限制$q并发性的大量阅读,并知道有些库可以提供帮助,但我真的很想了解为什么会这样做不能一直工作:)

1 个答案:

答案 0 :(得分:0)

您返回的承诺($q.all)并不能真正表明您实际想要返回的承诺。在上面的代码中,返回的承诺将在第一个maxConcurrentChunks得到解决后完成,因为当您将chunkPromises传递给$q.all()时,var uploadInChunks = function(file){ //...vars... var fileCompleteDeferral = $q.defer(); var queueChunks = function(){ chunkPromises.push(nextChunk(chunkIndex).then(function () { activePromises--; if(allChunksDone()) { //could be activePromises == 0, or chunkIndex == totalChunks - 1 fileCompleteDeferral.resolve(); } else { queueChunks(); } }); } return fileCompleteDeferral.promise.then(completeFile()); } 中承诺的承诺数量为多少。

处理此问题的另一种方法(并获得您想要的结果)将是以下伪造的代码:

MTLDevice newLibraryWithSource:options:error:

此代码返回的承诺只会在所有承诺完成后解决,而不仅仅是前8个承诺。