1

我是 RXJS 的新手,我发现 Redux-observable 使用 takeUntil 取消异步请求非常有用。但是当我测试它时,我发现即使我们取消了请求,实际的请求仍在进行中..

我有这个 JSbin 代码片段要测试。

https://jsbin.com/hujosafocu/1/edit?html,js,输出

即使您通过单击取消(多次)按钮取消请求,此处实际请求也不会取消。

我不确定这应该是怎样的......如果是,那么取消异步请求意味着什么。我有点困惑..请分享一些想法..

对此的任何回应将不胜感激..谢谢

4

2 回答 2

4

这个问题非常微妙,但显然很重要。鉴于您的代码:

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .delay(2000) // <-- while we're waiting, there is nothing to cancel!
    .mergeMap(action =>
      Observable.fromPromise(
        jQuery.getJSON('//api.github.com/users/redux-observable', data => {
          alert(JSON.stringify(data));
        })
      )
      .map(fetchUserFulfilled)
      .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );

踢球者是.delay(2000). 这就是说,“直到 2000 毫秒之后才向链的其余部分发出动作”。因为您的.takeUntil(action$.ofType(FETCH_USER_CANCELLED))取消逻辑在mergeMap的投影函数中,所以它还没有监听,FETCH_USER_CANCELLED因为还没有什么可以取消的!

如果您真的想在进行 ajax 调用之前引入任意延迟,但同时取消延迟或待处理的 ajax(如果它到达那里),您可以使用Observable.timer()

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      Observable.timer(2000)
        .mergeMap(() =>
          Observable.fromPromise(
            jQuery.getJSON('//api.github.com/users/redux-observable', data => {
              alert(JSON.stringify(data));
            })
          )
          .map(fetchUserFulfilled)
        )
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );

我想您并不在实际应用程序中调用 ajax 之前引入任意延迟,在这种情况下,此问题将不存在,文档中的示例是一个很好的入门参考。


需要注意的另一件事是,即使没有延迟或计时器,从代码中取消 ajax 请求也不会取消真正的底层 XMLHttpRequest——它只是忽略响应。这是因为 Promise 是不可取消的。

相反,我强烈推荐使用 RxJS's AjaxObservable,它可取消的:

Observable.ajax.getJSON('//api.github.com/users/redux-observable')

这可以通过多种方式导入。如果你已经导入了所有的 RxJS a la import 'rxjs';,它可以按预期使用。否则,还有其他几种方法:

import { ajax } from 'rxjs/observable/dom/ajax';

ajax.getJSON('/path/to/thing');

// or

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/dom/ajax';

Observable.ajax.getJSON('/path/to/thing');

重要的是要记住,就像所有的 Observable 工厂一样,它Observable.ajax惰性的,这意味着它不会发出 AJAX 请求,直到有人订阅它!马上jQuery.getJSON就能做到。

所以你可以像这样把它放在一起:

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      Observable.timer(2000)
        .mergeMap(() =>
          Observable.ajax.getJSON('//api.github.com/users/redux-observable')
            .do(data => alert(JSON.stringify(data)))
            .map(fetchUserFulfilled)
        )
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );

可以在这里找到一个工作演示:https ://jsbin.com/podoke/edit?js,output

于 2016-11-23T07:19:56.357 回答
0

这可能对将来的某人有所帮助..

就像上面提到的 jayphelps 一样,更好的解决方案是使用 RXjs AjaxObservable,因为它取消了实际的 XMLHttpRequest 而不是忽略响应。

但目前 RxJS v5 “RxJS Observable.ajax 跨域问题”存在一些问题

我发现的好解决方案是“允许绕过默认配置”,如下所示:

     const fetchUserEpic = action$ =>
              action$.ofType(FETCH_USER)
                .mergeMap(action =>
                  Observable.timer(2000)
                    .mergeMap(() =>
                        Observable.ajax({
                            url:`//api.github.com/users/redux-observable`,
                            crossDomain: true
                        })
                        .do(data => alert(JSON.stringify(data)))
                        .map(fetchUserFulfilled)
                    )
                    .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
                );

https://github.com/ReactiveX/rxjs/issues/1732

于 2016-11-24T05:28:06.193 回答