return 像 returning promises 一样可以被调用者函数观察到

return observable to the caller function like returning promises

我目前正在从 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() 和 return 以便调用函数也将等待 promise。但是对于 observable,正确的做法是什么?
我到底应该在哪里订阅,我应该在哪里映射值和 return 可观察值?

map 应该在你想修改发送的数据时使用,这样做会创建一个新的 Observable.

示例:

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

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

的请求

小心:

调用subscribe两次会触发Observable两次,也就是说如果你在一个基于http请求的Observable上调用subscribe,请求就会完成两次。

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

假设您的函数将在执行 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;
          });
    }

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

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

异步管道

大多数时候你并不需要使用 subscribe,你可以让 angular 为你处理,使用 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>