0

Я создаю приложение, используя Angular2. Я пытаюсь сделать многостраничную загрузку на Amazon S3. Мне нужно показать «Успех» или «Неудачный» тостер, основанный на успешной загрузке/сбое объекта. У меня есть «обещания», связанные с моим кодом. Но Тостер успеха показывается, даже до того, как обещание будет завершено. Я не уверен, что здесь происходит не так. Может кто-то, пожалуйста, помогите мне здесь.Ожидание Promise-Angular 2

Это звонящий:

this.multipartupload(params).then((data) => { 

      var fileNameArr = params.Key.split('/') 
      this.uiService.showMessage('success', fileNameArr[fileNameArr.length - 1] + ' Uploaded'); 

     }).catch((err) => { 
     this.uiService.showMessage('warning', err.message); 
     }) 

Multipart загрузка работает в трех различных стадиях: создание, загрузка и Complete. Я хочу показать сообщение об успешном завершении только после завершения этапа «Полный». Ниже приведен код, код «multipartUpload», которая вызывается из кода выше:

multipartupload(params: any){ 
     var s3 = this.getS3(); 
     var multipartParams = { 
     Bucket: params.Bucket, 
     Key: params.Key, 
     ServerSideEncryption: params.ServerSideEncryption 
     } 

     var partSize = 5 * 1024 * 1024; 
     var partNum = 0; 
     var multipartMap = { 
     Parts: [] 
     }; 
     var numPartsLeft = Math.ceil(params.Body.size/partSize); 
     return s3.createMultipartUpload(multipartParams).promise() 
     .then((data) => { 
      for(var rangeStart = 0; rangeStart < params.Body.size; rangeStart += partSize){ 
      var end = Math.min(rangeStart + partSize, params.Body.size); 
      partNum++; 
      var partParams = { 
       Body: params.Body.slice(rangeStart, end), 
       Bucket: params.Bucket, 
       Key: params.Key, 
       PartNumber: String(partNum), 
       UploadId: data.UploadId 
      } 
      return uploadPart(s3, data, partParams); // -> the toastr is shown at this point. I want it to wait till all the parts are uploaded. 
      } 
     }) 
     .catch((err) => { 
     return err; 
     }) 

     function uploadPart(s3, multipart, partParams, tryNum = 0){ 
     var tryNum = tryNum | 1; 
     s3.uploadPart(partParams).promise() 
      .then(
      (mData) => { 
       multipartMap.Parts[partParams.PartNumber - 1] = { 
       ETag: mData.ETag, 
       PartNumber: Number(partParams.PartNumber) 
       }; 
      if (--numPartsLeft > 0) return; 
      var doneParams = { 
       Bucket: params.Bucket, 
       Key: params.Key, 
       MultipartUpload: multipartMap, 
       UploadId: multipart.UploadId 
      }; 
      return s3.completeMultipartUpload(doneParams).promise().then((data) =>{ 
       return data; 
      }) 
      .catch((err) => { 
       return err; 
      }) 
      }) 
     .catch((multiErr) => { 
      if(tryNum < 3){ 
       uploadPart(s3, multipart, partParams, tryNum + 1); 
      } 
      return multiErr; 
      }) 
     } 
    } 

Я понимаю, что этот код немного долго. Но я хотел передать весь контекст. Спасибо за понимание. Я был бы признателен, если кто-то может поделиться, как подождать, пока последняя часть будет загружена успешно.

+0

Два вопроса: (1) является 'params.Body.size' синонимом' params.B ody.length'? (2) вы можете объяснить 'var tryNum = tryNum | 1, 'пожалуйста? –

+0

1) params.Body.size является синонимом params.Body.length. Я должен везде использовать params.Body.size. Я отредактирую код. 2) О да! Я могу установить значение по умолчанию tryNum равным 1, а не tryNum = tryNum | 1 – UnderWood

ответ

1

Казалось бы, что вам не хватает:

  • агрегацию обещаний, генерируемых в for цикле
  • пара возвращается

Здесь с немного дополнительной уборки .. .

this.multipartupload(params) 
.then((data) => { 
    var fileNameArr = params.Key.split('/'); 
    this.uiService.showMessage('success', fileNameArr[fileNameArr.length - 1] + ' Uploaded'); 
}).catch((err) => { 
    this.uiService.showMessage('warning', err.message); 
}); 

multipartupload(params: any) { 
    var s3 = this.getS3(), 
     partSize = 5 * 1024 * 1024, 
     partNum = 0, 
     multipartMap = { Parts: [] }; 
    var numPartsLeft = Math.ceil(params.Body.length/partSize); 
    return s3.createMultipartUpload({ 
     Bucket: params.Bucket, 
     Key: params.Key, 
     ServerSideEncryption: params.ServerSideEncryption 
    }).promise() 
    .then((data) => { 
     var promises = []; // <<<<<<< create an array of promises 
     for(var rangeStart = 0; rangeStart < params.Body.length; rangeStart += partSize) { 
      promises.push(uploadPart(s3, data, { 
       Body: params.Body.slice(rangeStart, Math.min(rangeStart + partSize, params.Body.length)), 
       Bucket: params.Bucket, 
       Key: params.Key, 
       PartNumber: String(++partNum), 
       UploadId: data.UploadId 
      }, 1)); 
     } 
     return Promise.all(promises) // <<<<<<< return a single aggregated promise. 
     .then((results => results.filter(res => res !== null))); // filter out any nulls delivered by the (--numPartsLeft > 0) condition below. 
    }); 

    function uploadPart(s3, multipart, partParams, tryNum) { 
     return s3.uploadPart(partParams).promise() 
    // ^^^^^^ 
     .then((mData) => { 
      multipartMap.Parts[partParams.PartNumber - 1] = { 
       ETag: mData.ETag, 
       PartNumber: Number(partParams.PartNumber) 
      }; 
      if (--numPartsLeft > 0) { 
       return null; 
      } 
      return s3.completeMultipartUpload({ 
       Bucket: params.Bucket, 
       Key: params.Key, 
       MultipartUpload: multipartMap, 
       UploadId: multipart.UploadId 
      }).promise(); 
     }).catch((multiErr) => (tryNum < 3) ? uploadPart(s3, multipart, partParams, tryNum + 1) : multiErr); // note the implicit return here. 
    } 
} 
+0

Мне было интересно об этой части. Я никогда не знал, что такое объединение обещаний возможно. Большое спасибо. Позвольте мне проверить это. – UnderWood

+0

Я использовал собственный синтаксис ES6 (и Bluebird) 'Promise.all()'. Поскольку вы находитесь в Angular, вам, вероятно, нужно '$ q.all()'. –

Смежные вопросы