Nested Observable/Promise (trying to block/wait flow in mapper function)

喜欢而已 提交于 2021-02-10 22:42:33

问题


I have the following code in an Angular app:

services$
  .pipe(
    map(serviceModels => {
      serviceModels
        .forEach((srv, srvIdx) => {
          // Resolve images in services
          srv.images.forEach(async (img, imgIdx) => {
            serviceModels[srvIdx].images[imgIdx] = await this.imageSrv.resolveImage(img).toPromise();
          });
        });
      return serviceModels;
  });
[...]  

Result is a single emition with one value change afterwards.

emit -> service.image[0] // 'unrendered-url' -> (wait) -> service.image[0] // correct-url/image-path

I'm trying to resolve the image from a service (this.imageSrv) that takes a string and returns a observable/promise with a rendered string. All I want is the code to block (or map() to hold the emition until the images are resolved) because I get two values in Angular for the services[0].images[0].

The easy way out is to put promises in the service[0].images array and img | async in the template engine, but I'd like to avoid that and maybe learn something new.


回答1:


You're currently trying to run new observables inside a map - which is for synchronously transforming the result of an observable into a different structure. I will ignore the attempt to await the promise, as that will be addressed by using the underlying observables directly.

The approach I'm going to take:

  • Use switchMap to chain an inner observable to the outer observable
  • Flatten the nested image arrays
  • Create an array of observables from the flattened image array
  • Run the observable array in a forkJoin
  • Update the resolved images in the serviceModels when the forkJoin completes
  • Return the serviceModels in a mapTo
services$.pipe(
  switchMap(serviceModels => {
    // flatten images
    const images = serviceModels.reduce((acc, srv) => acc.concat(srv.images), []);
    // map to array of observables
    const observables = images.map(img => this.resolveImage(img));

    // run observables in parallel
    return forkJoin(observables).pipe(
      tap(images => {
        // loop over original nested arrays
        // extract image from flattened images result
        let flatIdx = 0;
        serviceModels.forEach(srv => {
          srv.images.forEach((img, imgIdx) => {
            srv.images[imgIdx] = images[flatIdx++];
          });
        });
      }),
      // return serviceModels from the outer observable
      mapTo(serviceModels)
    )
  })
)
[...]  

By the way, I would recommend not overwriting the original images with the resolved images. While this is valid Javascript, you'll run into issues with Typescript if you're using types (and I don't see any reason not to).

DEMO: https://stackblitz.com/edit/angular-a6fblk



来源:https://stackoverflow.com/questions/60590846/nested-observable-promise-trying-to-block-wait-flow-in-mapper-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!