Angular 1服务 - RxJS共享运算符无法正常工作

时间:2017-06-14 10:21:46

标签: angularjs rxjs angularjs-service rxjs5

我创建了一个使用RxJS来回复$http次呼叫的服务。

我有几个订阅同一个observable的组件,我希望它们共享AJAX结果,而不是发出多个请求。

服务代码:

export function SearchService($http) {
    'ngInject';

    const autocompleteResults$ = new Subject()
        .debounceTime(250)
        .switchMap(query => Observable.fromPromise($http.post('/search', { query })))
        .share()
        .map(result => result.data);


    function autocomplete(query) {
        autocompleteResults$.next(query);
    }

    return {
        autocomplete,
        autocompleteResults$
    };
}

组件代码:

export const myComponent = {
    bindings: {
        query: '<'
    },
    templateUrl: templateUrl,
    controller: myController
};

function myController($SearchService) {
    'ngInject';
    const $ctrl = this;

    $ctrl.$onInit = $onInit;
    $ctrl.$onChanges = $onChanges;

    function $onInit() {
        SearchService.autocompleteResults$
            .subscribe(
                handleSuccess,
                handleError
            );
    }

    function $onChanges(changes) {
        if (changes.query && changes.query.currentValue)
            SearchService.autocomplete(changes.query.currentValue);
    }
}

我有 2 myComponent的有效组件来响应查询更改。

由于Angular服务是单例,每个组件在订阅它时应该获得相同的可观察实例,但总有2个AJAX调用而不是1个。

我尝试使用sharepublishpublishReplayshareReplayrefCount运营商但没有成功。

1 个答案:

答案 0 :(得分:1)

您所描述的内容似乎更像是在寻找缓存而不是共享和Observable。

当您使用share()时,您只是与其源Observable共享相同的订阅,而不是其结果。

例如,如果HTTP请求需要100毫秒,那么即使使用share(),这也会产生两个请求:

const source = this.http.get(...).share();
source.subscribe(...);

setTimeout(() => source.subscribe(...), 1000);

share()运算符在这里根本没有帮助,因为在第一个HTTP请求完成后,观察者取消订阅并且share()内的主题也取消订阅。然后在1秒后你再次订阅,它需要再次重新订阅,这会产生另一个HTTP请求。

但是,如果您执行了以下操作,那么您将只发出一个HTTP请求:

const source = this.http.get(...).share();
source.subscribe(...);
source.subscribe(...);

当第二个观察者订阅时,第一个观察者仍处于活动状态,并通过share()进行多播。因此,您只需拨打一个HTTP电话。

也许你正在寻找这样的东西,重播1s的收到价值:

const source = this.http.get(...)
    .publishReplay(1, 1000)
    .refCount()
    .take(1);