触发takeUntil操作时执行函数

时间:2018-02-01 17:49:09

标签: javascript reactjs rxjs rxjs5 redux-observable

我想在触发takeUntil运算符时执行一个函数(在ajaxObservable之外)。 In this way会立即被触发,因为我调用了observer.complete(),但是如果我没有调用它,那么会有内存泄漏吗? 什么是实现这个目标的好方法?

export const ajaxObservable = (url, method, data, params) => {
    let cancelToken = axios.CancelToke.source()
    return Observable
        .fromPromise(axios({/* axios params */}))
        .map(r => r.data)
        .catch(err => Observable.throw(err))
        .merge(
            new Observable(observer => {
                observer.complete()
                return () => cancelToke.cancel()
            })
        )
 }

1 个答案:

答案 0 :(得分:1)

您的方法存在的一个问题是,调用ajaxObservable()不会返回 lazy Observable。相反,即使没有人订阅返回的Observable,ajax require也会由axios立即生成。

虽然有例外情况,但通常最好让像这样的自定义Observable变得懒惰,因此对用户抱有相同的期望。

要做到这一点,你需要返回一个新的匿名Observable,非常类似于你如何使用Promises做到这一点。在我们的自定义Observable订阅处理程序中,不需要使用fromPromise或任何rxj,因为我们只需要调用axios和then

作为奖励,当我们这样做时,原始问题的解决方案变得更加明显:如果有人取消订阅,我们可以调用cancelToken.cancel()

export const ajaxObservable = (url, method, data, params) => {
    return new Observable(observer => {
        let cancelTokenSource = axios.CancelToken.source();
        let options = {
          url,
          method,
          data,
          params,
          withCredentials: true,
          cancelToken: cancelTokenSource.token
        };

        axios(options)
            .then(response => {
                observer.next(response.data);
                observer.complete(); // commonly forgotten, but critical!
            }, error => {
                observer.error(error);
            });

        return () => cancelTokenSource.cancel();
    });
};

btw .catch(err => Observable.throw(err))实际上是一个noop,再次重新抛出相同的错误。

您可能有兴趣知道rxjs带有一个AjaxObservable,这使得像axios这样的东西变得不必要了。遗憾的是,它的文档没有在rxjs v5文档中正确显示,但它可以在内联中找到:http://reactivex.io/rxjs/file/es6/observable/dom/AjaxObservable.js.html它有一个非常标准的API,与大多数ajax实用程序类似。

/**
 * Creates an observable for an Ajax request with either a request object with
 * url, headers, etc or a string for a URL.
 *
 * @example
 * source = Rx.Observable.ajax('/products');
 * source = Rx.Observable.ajax({ url: 'products', method: 'GET' });
 *
 * @param {string|Object} request Can be one of the following:
 *   A string of the URL to make the Ajax call.
 *   An object with the following properties
 *   - url: URL of the request
 *   - body: The body of the request
 *   - method: Method of the request, such as GET, POST, PUT, PATCH, DELETE
 *   - async: Whether the request is async
 *   - headers: Optional headers
 *   - crossDomain: true if a cross domain request, else false
 *   - createXHR: a function to override if you need to use an alternate
 *   XMLHttpRequest implementation.
 *   - resultSelector: a function to use to alter the output value type of
 *   the Observable. Gets {@link AjaxResponse} as an argument.
 */

它也有像ajax.getJSON等缩写。