RxJS sequence equivalent to promise.then()?

前端 未结 8 1355
南旧
南旧 2020-11-28 05:12

I used to develop a lot with promise and now I am moving to RxJS. The doc of RxJS doesn\'t provide a very clear example on how to move from promise chain to observer sequenc

相关标签:
8条回答
  • 2020-11-28 05:27

    if getPromise function is in a middle of a stream pipe you should simple wrap it into one of functions mergeMap, switchMap or concatMap (usually mergeMap):

    stream$.pipe(
       mergeMap(data => getPromise(data)),
       filter(...),
       map(...)
     ).subscribe(...);
    

    if you want to start your stream with getPromise() then wrap it into from function:

    import {from} from 'rxjs';
    
    from(getPromise()).pipe(
       filter(...)
       map(...)
    ).subscribe(...);
    
    0 讨论(0)
  • 2020-11-28 05:30

    Update May 2019, using RxJs 6

    Agree with the provided answers above, wished to add a concrete example with some toy data & simple promises (with setTimeout) using RxJs v6 to add clarity.

    Just update the passed id (currently hard-coded as 1) to something that does not exist to execute the error handling logic too. Importantly, also note the use of of with catchError message.

    import { from as fromPromise, of } from "rxjs";
    import { catchError, flatMap, tap } from "rxjs/operators";
    
    const posts = [
      { title: "I love JavaScript", author: "Wes Bos", id: 1 },
      { title: "CSS!", author: "Chris Coyier", id: 2 },
      { title: "Dev tools tricks", author: "Addy Osmani", id: 3 }
    ];
    
    const authors = [
      { name: "Wes Bos", twitter: "@wesbos", bio: "Canadian Developer" },
      {
        name: "Chris Coyier",
        twitter: "@chriscoyier",
        bio: "CSS Tricks and CodePen"
      },
      { name: "Addy Osmani", twitter: "@addyosmani", bio: "Googler" }
    ];
    
    function getPostById(id) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const post = posts.find(post => post.id === id);
          if (post) {
            console.log("ok, post found!");
            resolve(post);
          } else {
            reject(Error("Post not found!"));
          }
        }, 200);
      });
    }
    
    function hydrateAuthor(post) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const authorDetails = authors.find(person => person.name === post.author);
          if (authorDetails) {
            post.author = authorDetails;
            console.log("ok, post hydrated with author info");
            resolve(post);
          } else {
            reject(Error("Author not Found!"));
          }
        }, 200);
      });
    }
    
    function dehydratePostTitle(post) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          delete post.title;
          console.log("ok, applied transformation to remove title");
          resolve(post);
        }, 200);
      });
    }
    
    // ok, here is how it looks regarding this question..
    let source$ = fromPromise(getPostById(1)).pipe(
      flatMap(post => {
        return hydrateAuthor(post);
      }),
      flatMap(post => {
        return dehydratePostTitle(post);
      }),
      catchError(error => of(`Caught error: ${error}`))
    );
    
    source$.subscribe(console.log);
    

    Output Data:

    ok, post found!
    ok, post hydrated with author info
    ok, applied transformation to remove title
    { author:
       { name: 'Wes Bos',
         twitter: '@wesbos',
         bio: 'Canadian Developer' },
      id: 1 }
    

    The key part, is equivalent to the following using plain promise control flow:

    getPostById(1)
      .then(post => {
        return hydrateAuthor(post);
      })
      .then(post => {
        return dehydratePostTitle(post);
      })
      .then(author => {
        console.log(author);
      })
      .catch(err => {
        console.error(err);
      });
    
    0 讨论(0)
提交回复
热议问题