javascript - 使用 takeUntil 在 Redux-observable 中取消异步请求的预期行为是什么

标签 javascript asynchronous redux rxjs redux-observable

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

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

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

此处实际请求并未取消,即使您通过单击取消(多次)按钮取消了请求也是如此。

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

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

最佳答案

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

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 之前引入任意延迟,在这种情况下,这个问题将不存在并且 example in the docs是一个很好的入门引用。


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

相反,我强烈建议使用 RxJS 的 AjaxObservable,它是可取消的:

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

这可以通过多种方式导入。如果您已经通过 import 'rxjs'; 导入了所有 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

关于javascript - 使用 takeUntil 在 Redux-observable 中取消异步请求的预期行为是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40757112/

相关文章:

javascript - 带摄像头的旋转光源 + OrbitControls.js

javascript - 外部 JavaScript 文件已连接,但某些代码无法正常工作

javascript - 如何在同步模式下获取 outputStream block ?

JavaScript:如何确保此函数仅返回完全填充的数组?

javascript - 自定义组件无法在此基本 ReactJS 应用程序上正确呈现

javascript - 错误 : Actions must be plain objects. 使用自定义中间件进行异步操作。 React-redux 错误

javascript - 在 React Redux 中,如何重用执行 fetch 的钩子(Hook),而无需多次执行该 fetch?

javascript - 使用 JavaScript 从图像地址中获取图像名称

javascript - Bootstrap 4 : Modal won't show on my react app

javascript - 使用await关键字来模拟同步编程