以前做 React Native 时,需要对请求进行超时处理。然而,React Native 提供的 fetch
方法,根本没有提供超时的选择。于是只能自己玩些如下的黑科技了,代码一看就很乱,还难以维护:
const TIME_OUT = 3000;
let reqErrror = false;
let reqDone = false;
let timeout = setTimeout(() => {
// 超时错误
reqErrror = true;
// 标记本次请求结束
reqDone = true;
}, TIME_OUT);
fetch('/api/test')
.then(res => res.json())
.then((data) => {
clearTimeout(timeout);
// 没有错误发生
reqErrror = false;
// 标记本次请求结束
reqDone = true;
// ...
})
.catch((e) => {
clearTimeout(timeout);
// 发生某种错误
reqErrror = true;
// 标记本次请求结束
reqDone = true;
console.error(e);
});
那会儿刚开始接触,团队的几个人对 ES6 这些东西基本处在一种边学边用的状态,所以上面的方法在当时解决了问题,也还不错。后来离开项目,也许至今还在保留着这种方式吧。唉,当初的代码写得是有多乱啊,竟然都不会封装一下囧。
简单改写之后的代码如下:
const fetchWithTimeout = function(url = '', option = {}, timeout) {
if (!timeout) {
return fetch(url, option);
}
let timeout = new Promise(function (resolve, reject) {
setTimeout(function () {
let err = new Error('timeout');
reject(err);
}, timeout);
});
return Promise.race([
timeout,
fetch(url, option).then(res => res.json())
]);
};
fetchWithTimeout('/api/test', {}, TIME_OUT)
.then(res => res.json())
.then(data => {
// ...
})
.catch(e => {
// ...
});
好了,言归正传,其实这次我是要记录 Angular 2 中的 http 超时处理的,事情缘由不再赘述,和前面差不多。
同样我想到了 race
。 不过在 stackoverflow 中有人提过这个问题,是用 timeout
操作符,但我使用的时候遇到了一些问题。
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/race';
import 'rxjs/add/operator/delay';
const TIME_OUT = 3000;
// ...
let cancel$ = Observable.of(null).delay(TIME_OUT);
let request$ = this.http.get(url)
.map(res => res.json())
.catch(e => Observable.of(e));
let unsubscribe = request$.race(cancel$).subscribe(
data => console.log(data),
err => consoel.error(err),
() => console.log('complete');
);
// ...
暂且记录成这样吧,有空再补充。