如何延迟重试使用 RxJS5 发送 HTTP 请求?
How to delay retrying to send an HTTP request with RxJS5?
我在使 RxJS5 可观察流以我想要的方式运行时遇到问题。
流应该使用 axios 向网站发送 HTTP 请求,如果响应是 HTTP 错误(axios 强制转换为 JavaScript 错误),可观察序列应等待 10 毫秒,然后然后尝试重新发送请求(出于某种原因,当您立即重试发送请求并不断抛出错误时,我正在向其发送请求的网站不喜欢它,但大多数情况下在 10 毫秒延迟时表现良好)。
Rx.Observable
.fromPromise(axios('http://example.com/12345'))
.map(x => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 2000)
}))
.debounceTime(2000)
.do(console.log)
.retry(10)
.subscribe(console.log, console.error)
我在 Codepen 上有一个例子,做了一些改动,为了更清楚地说明流是如何工作的:http://codepen.io/leakyabstractions/pen/pNmvyZ?editors=0010
我尝试使用 .delay()
、.debounceTime()
、.timer()
、.timeInterval()
和 .timeout()
代替 .map()
运算符,但是没有任何效果(包括 .map()
)。我做错了什么?
所以基本上您要找的是 "retry after 10ms, but only 10 times"? (这就是您的 retry(10)
建议的内容。
我认为一个复杂的解决方案将包括 retryWhen
此处:
const mockedRestError$ = Rx.Observable.throw("http://example.com/12345");
// we'll start with an empty string, because otherwhise
// we could not log the "start..."
Rx.Observable.of("")
.do(() => console.log("start..."))
.switchMapTo(mockedRestError$)
.retryWhen(tenTimesWithDelay)
.subscribe(console.log, console.error, console.info); // is never called, because
function tenTimesWithDelay(errors) {
return errors
.scan((count, err) => {
++count;
// optionally to throw the error all the way down to the subscription
// comment the throw out to have the stream simply complete
if (count >= 10) {
throw err;
}
return count;
}, 0)
.takeWhile(count => count < 10)
.do(count => console.log(`Retry #${count} in 100ms...`))
.delay(100);
}
这里是代码笔:http://codepen.io/anon/pen/bBydwZ?editors=0010
另请注意,我将延迟设置为 100 毫秒而不是 10 毫秒,这样它在控制台中的显示会更清晰一些。
olsn 的回答有效,但我想分享另一个我无意中想出的解决方案,在我看来更直接一些:
console.log('start')
Rx.Observable
// emit observable every 10 ms, change to a bigger number to observe results
.interval(10)
// start immediately
.startWith(0)
// do it 10 times
.take(10)
.do(x => console.log('emitting', x))
// for every observable emitted, do an HTTP request
.flatMap(() => new Promise((resolve, reject) => resolve('resolved promise')))
.first(x => !(x instanceof Error))
.subscribe(console.log, console.warn, () => console.info('done'))
我在使 RxJS5 可观察流以我想要的方式运行时遇到问题。
流应该使用 axios 向网站发送 HTTP 请求,如果响应是 HTTP 错误(axios 强制转换为 JavaScript 错误),可观察序列应等待 10 毫秒,然后然后尝试重新发送请求(出于某种原因,当您立即重试发送请求并不断抛出错误时,我正在向其发送请求的网站不喜欢它,但大多数情况下在 10 毫秒延迟时表现良好)。
Rx.Observable
.fromPromise(axios('http://example.com/12345'))
.map(x => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 2000)
}))
.debounceTime(2000)
.do(console.log)
.retry(10)
.subscribe(console.log, console.error)
我在 Codepen 上有一个例子,做了一些改动,为了更清楚地说明流是如何工作的:http://codepen.io/leakyabstractions/pen/pNmvyZ?editors=0010
我尝试使用 .delay()
、.debounceTime()
、.timer()
、.timeInterval()
和 .timeout()
代替 .map()
运算符,但是没有任何效果(包括 .map()
)。我做错了什么?
所以基本上您要找的是 "retry after 10ms, but only 10 times"? (这就是您的 retry(10)
建议的内容。
我认为一个复杂的解决方案将包括 retryWhen
此处:
const mockedRestError$ = Rx.Observable.throw("http://example.com/12345");
// we'll start with an empty string, because otherwhise
// we could not log the "start..."
Rx.Observable.of("")
.do(() => console.log("start..."))
.switchMapTo(mockedRestError$)
.retryWhen(tenTimesWithDelay)
.subscribe(console.log, console.error, console.info); // is never called, because
function tenTimesWithDelay(errors) {
return errors
.scan((count, err) => {
++count;
// optionally to throw the error all the way down to the subscription
// comment the throw out to have the stream simply complete
if (count >= 10) {
throw err;
}
return count;
}, 0)
.takeWhile(count => count < 10)
.do(count => console.log(`Retry #${count} in 100ms...`))
.delay(100);
}
这里是代码笔:http://codepen.io/anon/pen/bBydwZ?editors=0010
另请注意,我将延迟设置为 100 毫秒而不是 10 毫秒,这样它在控制台中的显示会更清晰一些。
olsn 的回答有效,但我想分享另一个我无意中想出的解决方案,在我看来更直接一些:
console.log('start')
Rx.Observable
// emit observable every 10 ms, change to a bigger number to observe results
.interval(10)
// start immediately
.startWith(0)
// do it 10 times
.take(10)
.do(x => console.log('emitting', x))
// for every observable emitted, do an HTTP request
.flatMap(() => new Promise((resolve, reject) => resolve('resolved promise')))
.first(x => !(x instanceof Error))
.subscribe(console.log, console.warn, () => console.info('done'))