Nested Observable / Promise (пытается заблокировать / ждать поток в функции картографирования) - PullRequest
1 голос
/ 08 марта 2020

У меня есть следующий код в приложении Angular:

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;
  });
[...]  

Результатом является один выброс с последующим изменением значения.

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

Я пытаюсь разрешить изображение из сервиса (this.imageSrv ), который берет строку и возвращает наблюдаемое / обещание с визуализированной строкой. Все, что мне нужно, это код для блокировки (или map () для удержания выброса до разрешения изображений), потому что я получаю два значения в Angular для services[0].images[0].

Самый простой выход - это поместите обещания в массив service[0].images и img | async в шаблонизаторе, но я бы хотел этого избежать и, возможно, узнать что-то новое.

1 Ответ

3 голосов
/ 08 марта 2020

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

Подход, который я собираюсь предпринять:

  • Использование switchMap связать внутреннюю наблюдаемость с внешней наблюдаемой *
  • Обновите разрешенные изображения в serviceModels, когда forkJoin завершит
  • Верните serviceModels в 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)
    )
  })
)
[...]  

Кстати, я бы рекомендовал не перезаписывать исходные изображения разрешенными изображениями. Хотя это допустимо Javascript, у вас возникнут проблемы с Typescript, если вы используете типы (и я не вижу причин для этого).

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

...