RxJS: MergeMap with Preserving Input order

后端 未结 3 1033
悲哀的现实
悲哀的现实 2021-01-07 03:04

Requirement:

urls = [url1, url2, url3]

Fire all 3 urls parallely and paint the Dom in the sequnce of the urls list

 ex: Fini         


        
相关标签:
3条回答
  • 2021-01-07 03:33

    You can form a sequence with fetch and paint then forkJoin/Promise.all them

    p1 = fetch(url1)
    p2 = fetch(url2)
    p3 = fetch(url3)
    
    forkJoin(
    from(p1).pipe(tap(_=>paint dom...))
    from(p1).pipe(tap(_=>paint dom...))
    from(p1).pipe(tap(_=>paint dom...))
    ).subscribe()
    
    0 讨论(0)
  • 2021-01-07 03:36

    The best way to preserve order with async tasks like this is with concatMap.

    The problem is that if we apply this alone, we lose the parallelisation. If we were to do something like this:

    from(urls)
      .pipe(
          concatMap(x => fetch(x))
      )
    

    the second request is not fired until the first is complete.

    We can get around this by separating out the map into its own operator:

    from(urls)
      .pipe(
          map(x => fetch(x)),
          concatMap(x => x)
      )
    

    The request will all be fired at the same time, and the results will be emitted in request order.

    See Adrian's example adapted to use this approach below:

    const { from } = rxjs;
    const { concatMap, map } = rxjs.operators;
    
    function delayPromise(val, delay) {
      return new Promise(res => setTimeout(() => res(val), delay));
    }
    
    var delay = 3;
    
    
    from([1, 2, 3]).pipe(
      map(x => delayPromise(x, delay-- * 1000)),
      concatMap(x => x)
    ).subscribe(result => { console.log(result); });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>

    0 讨论(0)
  • 2021-01-07 03:52

    I couldn't find anything that preserves the order so I came up with something a bit convoluted.

    const { concat, of, BehaviorSubject, Subject } = rxjs;
    const { delay, filter } = rxjs.operators;
    
    const parallelExecute = (...obs$) => {
      const subjects = obs$.map(o$ => {
        const subject$ = new BehaviorSubject();
        const sub = o$.subscribe(o => { subject$.next(o); });
        return { sub: sub, obs$: subject$.pipe(filter(val => val)) };
      });
      const subject$ = new Subject();
      sub(0);
      function sub(index) {
        const current = subjects[index];
        current.obs$.subscribe(c => {
          subject$.next(c);
          current.obs$.complete();
          current.sub.unsubscribe();
          if (index < subjects.length -1) {
            sub(index + 1);
          } else {
            subject$.complete();
          }
        });
      }
      return subject$;
    }
    
    
    parallelExecute(
      of(1).pipe(delay(3000)),
      of(2).pipe(delay(2000)),
      of(3).pipe(delay(1000))
    ).subscribe(result => { console.log(result); });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>

    0 讨论(0)
提交回复
热议问题