axios-serializer
Version:
A serializer for axios
224 lines (220 loc) • 8.06 kB
JavaScript
import { __rest, __awaiter, __generator, __values } from 'tslib';
import axios from 'axios';
import { extend } from 'js-cool';
/**
* the config for retry when initialize and return
*
* @param config - SerializerRequestOptions
* @return currentState
*/
function getCurrentState(config) {
var currentState = config['axios-serializer'] || {};
currentState.retryCount = currentState.retryCount || 0;
config['axios-serializer'] = currentState;
return currentState;
}
/**
* AxiosSerializer class
*
* @return Promise
*/
var AxiosSerializer = /** @class */function () {
function AxiosSerializer(_a) {
var unique = _a.unique,
onCancel = _a.onCancel,
defaultOptions = __rest(_a, ["unique", "onCancel"]);
this.axiosInstance = null;
this.waiting = {}; // Request Queue
this.unique = false; // Whether to cancel the previous similar requests, default: false
this.orderly = true;
this.onCancel = null;
this.unique = unique !== null && unique !== void 0 ? unique : false;
this.onCancel = onCancel !== null && onCancel !== void 0 ? onCancel : null;
// Initialization method
this.init(defaultOptions);
return this;
}
/**
* Initialization
*/
AxiosSerializer.prototype.init = function (defaultOptions) {
var setHeaders = defaultOptions.setHeaders,
onRequest = defaultOptions.onRequest,
onRequestError = defaultOptions.onRequestError,
onResponse = defaultOptions.onResponse,
onResponseError = defaultOptions.onResponseError,
onError = defaultOptions.onError,
options = __rest(defaultOptions, ["setHeaders", "onRequest", "onRequestError", "onResponse", "onResponseError", "onError"]);
if (!this.axiosInstance) this.axiosInstance = axios.create(options);
// Set request headers
setHeaders && setHeaders(this.axiosInstance);
// Adding a request interceptor
onRequest && this.axiosInstance.interceptors.request.use(function (config) {
var currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
if (currentState.retryCount > 0) return config; // retry re-requests the interface without executing onRequest again
return onRequest(config, config.requestOptions);
}, function (err) {
onRequestError && onRequestError(err);
onError && onError(err);
return Promise.reject(err);
});
// Adding a response interceptor
onResponse && this.axiosInstance.interceptors.response.use(function (res) {
return onResponse(res, res.config.requestOptions);
}, function (err) {
var config = err.config;
// No request config
if (!config) {
onResponseError && onResponseError(err);
onError && onError(err);
return Promise.reject(err);
}
var currentState = getCurrentState(config);
currentState.retryCount += 1;
onResponseError && onResponseError(err);
onError && onError(err);
return Promise.reject(err);
});
};
/**
* Create request
*/
AxiosSerializer.prototype.create = function (
// url: string | SerializerRequestOptions<D>,
config) {
return __awaiter(this, void 0, void 0, function () {
var _a, unique, _b, orderly, _c, url, promiseKey, source, abortController, promise;
var _this = this;
return __generator(this, function (_d) {
_a = config.unique, unique = _a === void 0 ? this.unique : _a, _b = config.orderly, orderly = _b === void 0 ? this.orderly : _b, _c = config.url, url = _c === void 0 ? '' : _c;
promiseKey = Symbol('promiseKey');
source = axios.CancelToken.source();
config.requestOptions = extend(true, {}, config);
config.cancelToken = source.token;
if (typeof AbortController === 'function') {
abortController = new AbortController();
config.signal = abortController.signal;
}
// Interface must return in order or need to cancel url same request
unique && this.clear(config.url);
promise = new Promise(function (resolve, reject) {
_this.axiosInstance(config).then(function (res) {
if (!orderly) resolve(res);else _this.wait(config.url, promiseKey).then(function () {
resolve(res);
});
}).catch(function (err) {
// Request cancelled
if (axios.isCancel(err)) _this.onCancel && _this.onCancel(err);
// Request error
else reject(err);
}).finally(function () {
var index = _this.waiting[config.url].findIndex(function (el) {
return el.promiseKey === promiseKey;
});
index > -1 && _this.waiting[config.url].splice(index, 1);
});
});
this.add(config.url, {
promiseKey: promiseKey,
url: url,
promise: promise,
source: source,
abortController: abortController
});
return [2 /*return*/, promise];
});
});
};
/**
* Drop all un-need requests
*
* @param key - the key of waiting line, usually to be the request url
*/
AxiosSerializer.prototype.clear = function (key) {
var e_1, _a;
for (var url in this.waiting) {
// no key => clean all
if (!key || url === key) {
var waitingList = this.waiting[url] || [];
try {
for (var waitingList_1 = (e_1 = void 0, __values(waitingList)), waitingList_1_1 = waitingList_1.next(); !waitingList_1_1.done; waitingList_1_1 = waitingList_1.next()) {
var item = waitingList_1_1.value;
item.source.cancel('request canceled');
item.abortController && item.abortController.abort();
}
} catch (e_1_1) {
e_1 = {
error: e_1_1
};
} finally {
try {
if (waitingList_1_1 && !waitingList_1_1.done && (_a = waitingList_1.return)) _a.call(waitingList_1);
} finally {
if (e_1) throw e_1.error;
}
}
this.waiting[url] = [];
}
}
};
/**
* Waiting to resolve the item before this request
*
* @param key - the key of waiting line, usually to be the request url
* @param promiseKey - the unique promise key
* @returns - Promise<void>
*/
AxiosSerializer.prototype.wait = function (key, promiseKey) {
return __awaiter(this, void 0, void 0, function () {
var waitingList, index;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.orderly) return [2 /*return*/, Promise.resolve()];
waitingList = this.waiting[key] || [];
index = waitingList.findIndex(function (item) {
return item.promiseKey === promiseKey;
});
_b.label = 1;
case 1:
if (!(index > 0)) return [3 /*break*/, 7];
index--;
if (!(waitingList[index] && waitingList[index].promiseKey !== promiseKey)) return [3 /*break*/, 6];
_b.label = 2;
case 2:
_b.trys.push([2, 4,, 5]);
return [4 /*yield*/, waitingList[index].promise
// await waitingList.splice(index, 1)[0].promise
];
case 3:
_b.sent();
return [3 /*break*/, 5];
case 4:
_b.sent();
console.info('The task has been dropped');
return [3 /*break*/, 5];
case 5:
waitingList.splice(index, 1);
_b.label = 6;
case 6:
return [3 /*break*/, 1];
case 7:
return [2 /*return*/];
}
});
});
};
/**
* set item to waiting list
*
* @param key - the key of waiting line, usually to be the request url
* @param item - waiting object
*/
AxiosSerializer.prototype.add = function (key, item) {
if (!(key in this.waiting)) this.waiting[key] = [];
this.waiting[key].push(item);
};
return AxiosSerializer;
}();
export { AxiosSerializer as default };