简体   繁体   中英

Waiting for Promise- Angular 2

I am building an application using Angular2. I am trying to do a Multipart upload to Amazon S3. I need to show a 'Success' or a 'Failed' toaster based on successfully uploading/failing an object. I have 'promises' involved in my code. But the Success toaster is being shown, even before the promise is completed. I am not sure what is going wrong here. Can someone please help me here.

This is the caller:

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 upload works in three different stages: Create, Upload and Complete. I want to show the success message only after the 'Complete' stage is completed. Below is the code code for ' multipartUpload ', which is called from the above code:

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

I understand that this code is a little long. But I wanted to convey the whole context. Thanks for understanding. I would appreciate if someone can share on how to wait till the last part is uploaded successfully.

It would appear that you are missing :

  • aggregation of promises generated in the for loop
  • a couple of returns

Here it is with a bit of additional tidying ...

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.
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM