使用 takeUntil 在 Redux-observable 中取消异步请求的预期行为是什么
What is the expected behaviour Cancelling async request in Redux-observable using takeUntil
我是 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)
。这就是说,"don't emit the action to the rest of the chain until after 2000ms"。因为您的 .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 的 real——它只是忽略响应。这是因为 Promise 是不可取消的。
相反,我强烈建议使用 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
是 lazy 这意味着它不会发出 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
这可能对以后的人有帮助..
像上面提到的 jayphelps 一样,更好的解决方案是使用 RXjs AjaxObservable,因为它取消了实际的 XMLHttpRequest 而不是忽略响应。
但目前 RxJS v5 存在一些问题 "RxJS Observable.ajax cross domain issue"
我找到的好的解决方案是 "allows bypassing default configurations"
如下所示:
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))
);
我是 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)
。这就是说,"don't emit the action to the rest of the chain until after 2000ms"。因为您的 .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 的 real——它只是忽略响应。这是因为 Promise 是不可取消的。
相反,我强烈建议使用 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
是 lazy 这意味着它不会发出 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
这可能对以后的人有帮助..
像上面提到的 jayphelps 一样,更好的解决方案是使用 RXjs AjaxObservable,因为它取消了实际的 XMLHttpRequest 而不是忽略响应。
但目前 RxJS v5 存在一些问题 "RxJS Observable.ajax cross domain issue"
我找到的好的解决方案是 "allows bypassing default configurations" 如下所示:
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))
);