【问题标题】:How can I chain HTTP calls in Angular 2?如何在 Angular 2 中链接 HTTP 调用?
【发布时间】:2016-03-10 08:21:02
【问题描述】:

我是 Angular 2 和 HTTP Observables 的新手。我有一个调用 HTTP 服务并返回 Observable 的组件。然后我订阅了那个 Observable,它工作正常。

现在,我希望在该组件中,在调用第一个 HTTP 服务之后,如果调用成功,则调用另一个 HTTP 服务并返回该 Observable。因此,如果第一次调用不成功,则组件返回该 Observable,相反,它返回第二次调用的 Observable。

链接 HTTP 调用的最佳方式是什么?有没有优雅的方式,比如monads

【问题讨论】:

    标签: http angular


    【解决方案1】:

    您可以使用mergeMap 运算符来执行此操作。

    Angular 4.3+(使用HttpClientModule)和RxJS 6+

    import { mergeMap } from 'rxjs/operators';
    
    this.http.get('./customer.json').pipe(
      mergeMap(customer => this.http.get(customer.contractUrl))
    ).subscribe(res => this.contract = res);
    

    Angular HttpModule)和RxJS

    导入运算符mapmergeMap,然后可以将两个调用链接如下:

    import 'rxjs/add/operator/map'; 
    import 'rxjs/add/operator/mergeMap';
    
    this.http.get('./customer.json')
      .map((res: Response) => res.json())
      .mergeMap(customer => this.http.get(customer.contractUrl))
      .map((res: Response) => res.json())
      .subscribe(res => this.contract = res);
    

    更多细节在这里:http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http

    更多关于mergeMap操作符的信息可以在here找到

    【讨论】:

    • 对于 Angular 2.0 (beta 0),需要以下内容: import 'rxjs/add/operator/map';导入'rxjs/add/operator/mergeMap';
    • 如果您使用的是 flatMap,为什么要导入 mergeMap?
    • flatMap 是一个别名
    • @TGH 所以呢?由于导入和使用不同,代码并不明显。我也有这个问题,我的其他同事也有。我敢打赌,因此会有很多问题。
    • 了解mergeMap/flatMap的好教程可以在这里找到blog.thoughtram.io/rx/2016/08/01/…
    【解决方案2】:

    使用 rxjs 来完成这项工作是一个很好的解决方案。容易阅读吗?我不知道。

    另一种方法是使用 await/async

    例子:

    async getContrat(){
        // Get the customer
        const customer = await this.http.get('./customer.json').toPromise();
    
        // Get the contract from the URL
        const contract = await this.http.get(customer.contractUrl).toPromise();
    
        return contract; // You can return what you want here
    }
    

    然后调用它:)

    this.myService.getContrat().then( (contract) => {
      // do what you want
    });
    

    或者在异步函数中:

    const contract = await this.myService.getContrat();
    

    您也可以使用 try/catch 来管理错误:

    let customer;
    try {
      customer = await this.http.get('./customer.json').toPromise();
    }catch(err){
       console.log('Something went wrong will trying to get customer');
       throw err; // Propagate the error
       //customer = {};  // It's a possible case
    }
    

    【讨论】:

    • 花了很长时间关注 mergeMap 和 forkJoin 的示例,试图在 Angular 8 中对另一个 HTTP 调用的响应中的每个元素进行 HTTP 调用,但在与我的同行讨论之后,他们非常喜欢像这样的简单异步的可读性。 +1 表示不会为了使用反应函数而尝试使用反应函数而陷入过度工程的兔子洞。
    • 这比 rxjs 的方式简单得多。我更喜欢这个。
    【解决方案3】:

    你也可以链接 Promise。按照这个例子

    <html>
    <head>
      <meta charset="UTF-8">
      <title>Chaining Promises</title>
    </head>
    
    <body>
    
      <script>
        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) {
          // Create a new promise
          return new Promise((resolve, reject) => {
             // Using a settimeout to mimic a database/HTTP request
             setTimeout(() => {
               // Find the post we want
               const post = posts.find(post => post.id == id);
               if (post) {
                  resolve(post) // Send the post back
               } else {
                  reject(Error('No Post Was Found!'));
               }
             },200);
          });
        }
    
        function hydrateAuthor(post) {
           // Create a new promise
           return new Promise((resolve, reject) => {
             // Using a settimeout to mimic a database/http request
             setTimeout(() => {
               // Find the author
               const authorDetails = authors.find(person => person.name === post.author);
               if (authorDetails) {
                 // "Hydrate" the post object with the author object
                 post.author = authorDetails;
                 resolve(post);
               }
               else {
                  reject(Error('Can not find the author'));
               }
             },200);
           });
        }
    
        getPostById(4)
          .then(post => {
             return hydrateAuthor(post);
          })
          .then(post => {
             console.log(post);
          })
          .catch(err => {
             console.error(err);
          });
      </script>
    
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-31
      • 2018-07-08
      • 1970-01-01
      • 2018-08-30
      • 1970-01-01
      相关资源
      最近更新 更多