【问题标题】:return observable to the caller function like returning promises像返回承诺一样返回可观察到的调用者函数
【发布时间】:2017-04-04 04:16:57
【问题描述】:

我目前正在从 angular 1.x 迁移到 angular 2。该应用程序目前遵循 John Papa 的风格指南Return a Promise from Data Calls

activate();

function activate() {
    /**
     * Step 1
     * Ask the getAvengers function for the
     * avenger data and wait for the promise
     */
    return getAvengers().then(function() {
        /**
         * Step 4
         * Perform an action on resolve of final promise
         */
        logger.info('Activated Avengers View');
    });
}

function getAvengers() {
      /**
       * Step 2
       * Ask the data service for the data and wait
       * for the promise
       */
      return dataservice.getAvengers()
          .then(function(data) {
              /**
               * Step 3
               * set the data and resolve the promise
               */
              vm.avengers = data;
              return vm.avengers;
      });
}

如何使用 Observables 做同样的事情?有了promise,我可以在多个函数中写.then() 并返回它,这样调用者函数也将等待promise。但是对于可观察的,正确的做法是什么?
我应该在哪里订阅,我应该在哪里映射值并返回 observable?

【问题讨论】:

标签: angular angular2-observables


【解决方案1】:

map 应该在您想要修改发送的数据时使用,并通过这样做创建一个新的Observable

示例:

getAvengers.map(avengers => avengers.forEach(a => a.kill)) 将创建一个可观察到的已死复仇者。然后你可以订阅这个 observable 来调用死亡复仇者的方法。

subscribe 更像then,因为它只是等待数据调用传递给它的方法。但是 subscribe 会触发 observable,这意味着如果你只是调用getAvengers()(假设getAvengers 返回一个Observable)你会得到一个Observable,来触发你必须subscribe 的请求。

小心:

调用subscribe 两次将触发Observable 两次,这意味着如果您基于http 请求在Observable 上调用subscribe,该请求将被执行两次。

因此,您可以使用带有 observable 的缓存来处理此问题,但文档将能够指导您完成此操作。

【讨论】:

    【解决方案2】:

    在使用 Promise 时,你使用 .then(),使用 Observables,你有很多 operators 可以让你组合多个 observables,创建副作用,修改初始 observable 发出的值等。map 如 @ 解释Supamiu 就是所有这些运算符的一个例子。

    Observables 不按原样做任何事情,它们定义了一个数据流,它只是触发数据广播过程的订阅。

    异步管道

    大多数时候你真的不需要使用subscribe,你可以使用async管道为你制作角度手柄。例如:

    组件:

    this.avengers$=this.dataservice.getAvengers().do(()=>console.log("Avengers fetched");
    

    模板:

    <span *ngFor="avenger of avengers$|async">{{avenger.name}}</span>
    

    它定义了数据流这一事实允许您对创建非常复杂的流的事件做出反应,而不会产生太多副作用或努力。

    例如在点击时创建新的复仇者:

    组件:

    avengerClick$ = new Subject<mouseEvent>();
    
    constructor(){
        let initialAvengers = this.dataservice.getAvengers().do(()=>console.log("Avengers fetched").switchMap(avangers);
        this.avengers$ = Observable.merge(
            initialAvengers,
            this.avengerClick.switchMap(()=>this.dataservice.createAvenger()) // let's say this.dataservice.createAvenger() returns the new list of avengers
        )
    }
    

    模板:

    <span *ngFor="avenger of avengers$|async">{{avenger.name}}</span>
    <span (click)="avengerClick$.next($event)">Create an avenger</span>
    

    【讨论】:

      【解决方案3】:

      假设您的函数将在执行 http 请求之前调用其中的多个函数。

      function A() {
        B().subscribe();
      }
      
      function B() {
        return C().map();
      }
      
      function C() {
        return D().map();
      }
      
      function D() {
       // call http reuest and return data
      }
      

      调用者函数将执行实际订阅,所有其他参与的函数将简单地映射数据。

      来到你的代码,你将不得不这样修改:

      activate();
      
          function activate() {
              /**
               * Step 1
               * Ask the getAvengers function for the
               * avenger data and wait for the promise
               */
              return getAvengers().subscribe(
                  (data) => {
                  // handle your result data
                  logger.info('Activated Avengers View');
              });
          }
      
          function getAvengers() {
                /**
                 * Step 2
                 * Ask the data service for the data and wait
                 * for the promise
                 */
                return dataservice.getAvengers()
                    .map((data) => {
                        /**
                         * Step 3
                         * set the data and resolve the Observable
                         */
                        vm.avengers = data;
                        return vm.avengers;
                });
          }
      

      【讨论】:

        猜你喜欢
        • 2019-07-23
        • 2019-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-15
        • 2016-10-24
        • 2015-06-20
        • 2015-11-27
        相关资源
        最近更新 更多