for await()

in lib/lib-storage/src/Upload.ts [226:331]


    for await (const dataPart of dataFeeder) {
      if (this.uploadEnqueuedPartsCount > this.MAX_PARTS) {
        throw new Error(
          `Exceeded ${this.MAX_PARTS} parts in multipart upload to Bucket: ${this.params.Bucket} Key: ${this.params.Key}.`
        );
      }

      if (this.abortController.signal.aborted) {
        return;
      }

      // Use put instead of multipart for one chunk uploads.
      if (dataPart.partNumber === 1 && dataPart.lastPart) {
        return await this.__uploadUsingPut(dataPart);
      }

      if (!this.uploadId) {
        const { UploadId } = await this.__createMultipartUpload();
        this.uploadId = UploadId;
        if (this.abortController.signal.aborted) {
          return;
        }
      }

      const partSize: number = byteLength(dataPart.data) || 0;

      const requestHandler = this.client.config.requestHandler;
      const eventEmitter: EventEmitter | null = requestHandler instanceof EventEmitter ? requestHandler : null;

      let lastSeenBytes = 0;
      const uploadEventListener = (event: ProgressEvent, request: HttpRequest) => {
        const requestPartSize = Number(request.query["partNumber"]) || -1;

        if (requestPartSize !== dataPart.partNumber) {
          // ignored, because the emitted event is not for this part.
          return;
        }

        if (event.total && partSize) {
          this.bytesUploadedSoFar += event.loaded - lastSeenBytes;
          lastSeenBytes = event.loaded;
        }

        this.__notifyProgress({
          loaded: this.bytesUploadedSoFar,
          total: this.totalBytes,
          part: dataPart.partNumber,
          Key: this.params.Key,
          Bucket: this.params.Bucket,
        });
      };

      if (eventEmitter !== null) {
        // The requestHandler is the xhr-http-handler.
        eventEmitter.on("xhr.upload.progress", uploadEventListener);
      }

      this.uploadEnqueuedPartsCount += 1;

      const partResult = await this.client.send(
        new UploadPartCommand({
          ...this.params,
          // dataPart.data is chunked into a non-streaming buffer
          // so the ContentLength from the input should not be used for MPU.
          ContentLength: undefined,
          UploadId: this.uploadId,
          Body: dataPart.data,
          PartNumber: dataPart.partNumber,
        })
      );

      if (eventEmitter !== null) {
        eventEmitter.off("xhr.upload.progress", uploadEventListener);
      }

      if (this.abortController.signal.aborted) {
        return;
      }

      if (!partResult.ETag) {
        throw new Error(
          `Part ${dataPart.partNumber} is missing ETag in UploadPart response. Missing Bucket CORS configuration for ETag header?`
        );
      }

      this.uploadedParts.push({
        PartNumber: dataPart.partNumber,
        ETag: partResult.ETag,
        ...(partResult.ChecksumCRC32 && { ChecksumCRC32: partResult.ChecksumCRC32 }),
        ...(partResult.ChecksumCRC32C && { ChecksumCRC32C: partResult.ChecksumCRC32C }),
        ...(partResult.ChecksumSHA1 && { ChecksumSHA1: partResult.ChecksumSHA1 }),
        ...(partResult.ChecksumSHA256 && { ChecksumSHA256: partResult.ChecksumSHA256 }),
      });

      if (eventEmitter === null) {
        this.bytesUploadedSoFar += partSize;
      }

      this.__notifyProgress({
        loaded: this.bytesUploadedSoFar,
        total: this.totalBytes,
        part: dataPart.partNumber,
        Key: this.params.Key,
        Bucket: this.params.Bucket,
      });
    }