|
|
@@ -21,10 +21,73 @@ function checkStatus(response) {
|
|
|
* @param {object} [options] The options we want to pass to "fetch"
|
|
|
* @return {object} An object containing either "data" or "err"
|
|
|
*/
|
|
|
+
|
|
|
+class TimeoutError extends Error {
|
|
|
+ constructor(message) {
|
|
|
+ super(message);
|
|
|
+ this.name = 'TimeoutError';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 提供参数校验和wrapper功能
|
|
|
+ *
|
|
|
+ * @param {*} url
|
|
|
+ * @param {*} [options={ method: 'GET' }]
|
|
|
+ * @returns {Promise} the request result
|
|
|
+ */
|
|
|
export default function request(url, options) {
|
|
|
- return fetch(url, options)
|
|
|
- .then(checkStatus)
|
|
|
- .then(parseJSON)
|
|
|
- .then(data => ({ data }))
|
|
|
- .catch(err => ({ err }));
|
|
|
+ let retryCount = 0;
|
|
|
+
|
|
|
+ class Request {
|
|
|
+ constructor(url, {
|
|
|
+ retry,
|
|
|
+ timeout,
|
|
|
+ ...options
|
|
|
+ }) {
|
|
|
+ this.url = url;
|
|
|
+ this.retry = retry || 0;
|
|
|
+ this.timeout = timeout || 30000;
|
|
|
+ this.options = options;
|
|
|
+ }
|
|
|
+
|
|
|
+ then(fn) {
|
|
|
+ let done = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ // 无论是请求重试还是最终超时错误,此次请求得到的结果作废
|
|
|
+ if (retryCount < this.retry && !done) {
|
|
|
+ done = true;
|
|
|
+ retryCount++;
|
|
|
+ this.then(fn);
|
|
|
+ } else {
|
|
|
+ let error = new TimeoutError(`timeout of ${this.timeout}ms execeeded`);
|
|
|
+ this.catchError(error);
|
|
|
+ }
|
|
|
+ }, this.timeout);
|
|
|
+
|
|
|
+ fetch(this.url, this.options)
|
|
|
+ .then(checkStatus)
|
|
|
+ .then(parseJSON)
|
|
|
+ .then(data => {
|
|
|
+ // 未进入重试或者超时错误,返回结果
|
|
|
+ if (!done) {
|
|
|
+ fn({data});
|
|
|
+ done = true;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ this.catchError(err);
|
|
|
+ });
|
|
|
+
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ catch (fn) {
|
|
|
+ this.catchError = fn;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Promise((resolve, reject) =>
|
|
|
+ new Request(url, options).then(res => resolve(res)).catch(err => reject(err))
|
|
|
+ );
|
|
|
}
|