-1

I have a piece of code which uses and returns a promise. However, I want to convert it to an observable. Please advice.

Original code:

export const uploadMultipleFilesToAzure = (
  uploadData: Omit<UploadMultipleToAzure, 'id'>[],
  handleProgress: (
    loadedBytes: number,
    fileData: UploadMultipleToAzure['fileData'],
    uploadId: Upload['id']
  ) => void,
  individualCallback: Function
): Promise<BlockBlobUploadHeaders[]> => {
  const PIPELINE: Pipeline = newPipeline(new AnonymousCredential(), {
    retryOptions: { maxTries: 4 }, // Retry options
    keepAliveOptions: {
      // Keep alive is enabled by default, disable keep alive by setting false
      enable: false,
    },
  });

  const promises: Promise<BlobUploadCommonResponse>[] = [];
  forEach(uploadData, (uploadItem) => {
    let blockBlobClient: BlockBlobClient = new BlockBlobClient(
      uploadItem.BlobURL,
      PIPELINE
    );
    promises.push(
      (
        blockBlobClient.uploadData(uploadItem.fileData as Blob, {
          blockSize:
            (uploadItem.fileData as Blob).size > 1024 * 1024 * 32
              ? 1024 * 1024 * 4
              : 1024 * 512,
          maxSingleShotSize: 1024 * 512,
          concurrency: 20, // 20 concurrency,
          onProgress: (ev: TransferProgressEvent) =>
            handleProgress(
              ev.loadedBytes / (uploadItem.fileData as Blob).size,
              uploadItem.fileData,
              uploadItem.id
            ),
        }) as any
      ).then(() => {
        individualCallback(uploadItem);
      })
    );
  });
  return Promise.all(promises);
};
arunmmanoharan
  • 2,535
  • 2
  • 29
  • 60
  • 1
    I'm unclear on your question. Are you looking to convert a `Promise` to an Observable? If so, `from(promise)` works: https://stackoverflow.com/questions/39319279/convert-promise-to-observable. Or are you looking to completely rewrite this code using an Observable-based approach instead of a promise? If so, is there a specific question about the process that you have? – DeborahK Jul 12 '21 at 21:08
  • Yes, I want to rewrite this using observables. I understand that forkJoin or combineLatest would do the trick but not sure on how to proceed further. – arunmmanoharan Jul 12 '21 at 21:09
  • There isn't a one-to-one line change to change code from promise based to Observable based. Rather, you need to rethink it in terms of emissions and notifications. Can you build a *SMALL* demo (not your entire app) in Stackblitz to show what you've tried so far? – DeborahK Jul 13 '21 at 19:07

1 Answers1

0

This looks to me like a straightforward forkJoin situation.

Simplifying, you have:

const uploadMultipleFilesToAzure = (uploads: any[]) =>
  forkJoin(uploads.map(upload => 
    upload.somethingReturningPromise(prms)
  );

This is simply replacing the Promises.all with the forkJoin. forkJoin can takes promises as input, and will emit a single event with the array of results.

Where you have the inner "then" this changes to an xMap - let's assume mergeMap. You will now need from() to convert from a promise to an observable:

const uploadMultipleFilesToAzure = (uploads: any[]) =>
  forkJoin(uploads.map(upload => 
    from(upload.somethingReturningPromise(prms)).pipe(
      mergeMap( ()=> individualCallback(uploadItem);
    )
  );

Finally, if you use forkJoin or from() then the promise will be invoked when this function (to create the observable) is called, rather than when the observable is subscribed to. For this reason it is generally better to use defer() instead:

  const uploadMultipleFilesToAzure = (uploads: any[]) =>
    forkJoin(uploads.map(upload => 
      defer(() => upload.somethingReturningPromise(prms)).pipe(
        mergeMap( ()=> individualCallback(uploadItem);
      )
    );
James Y
  • 161
  • 6