axios-series
Version:
A tool to extend axios to return sequentially
372 lines (365 loc) • 12.8 kB
JavaScript
/*!
* axios-series v1.2.0
* A tool to extend axios to return sequentially
* (c) 2021-2023 saqqdy
* Released under the MIT License.
*/
this.axiosSeries = (function (axios) {
'use strict';
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = {
label: 0,
sent: function sent() {
if (t[0] & 1) throw t[1];
return t[1];
},
trys: [],
ops: []
},
f,
y,
t,
g;
return g = {
next: verb(0),
"throw": verb(1),
"return": verb(2)
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
return this;
}), g;
function verb(n) {
return function (v) {
return step([n, v]);
};
}
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return {
value: op[1],
done: false
};
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2]) _.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
} catch (e) {
op = [6, e];
y = 0;
} finally {
f = t = 0;
}
if (op[0] & 5) throw op[1];
return {
value: op[0] ? op[1] : void 0,
done: true
};
}
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator,
m = s && o[s],
i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function next() {
if (o && i >= o.length) o = void 0;
return {
value: o && o[i++],
done: !o
};
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var Serializer = /** @class */function () {
function Serializer(instance, options) {
this.waiting = {};
this.unique = false;
this.orderly = true;
this.onCancel = null;
var defaultOptions = {
unique: false,
orderly: true
};
options = Object.assign(defaultOptions, options || {});
this.axiosInstance = instance;
this.unique = options.unique;
this.orderly = options.orderly;
options.onCancel && (this.onCancel = options.onCancel);
}
/**
* Do request
*
* @param config - axios request config
* @returns - Promise<unknown>
*/
// public async request<T = any, R = AxiosResponse<T>, D = any>(
// config: SerializerRequestOptions<D>
// ): Promise<R>
// public async request<T = any, R = AxiosResponse<T>, D = any>(
// url: string,
// config?: SerializerRequestOptions<D>
// ): Promise<R>
Serializer.prototype.request = 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, {}, options)
config.cancelToken = source.token;
if (typeof AbortController === 'function') {
abortController = new AbortController();
config.signal = abortController.signal;
}
unique && this.clear(url);
promise = new Promise(function (resolve, reject) {
_this.axiosInstance(config).then(function (res) {
if (!orderly) resolve(res);else _this.wait(url, promiseKey).then(function () {
resolve(res);
});
}).catch(function (err) {
// Request cancelled
if (axios.isCancel(err)) _this.onCancel && _this.onCancel(err, config);
// Request error
else reject(err);
}).finally(function () {
var index = _this.waiting[url].findIndex(function (el) {
return el.promiseKey === promiseKey;
});
index > -1 && _this.waiting[url].splice(index, 1);
});
});
this.add(url, {
promiseKey: promiseKey,
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
*/
Serializer.prototype.clear = function (key) {
var e_1, _a;
for (var url in this.waiting) {
// no key => clean all
if (!key || url === key) {
var seriesList = this.waiting[url] || [];
try {
for (var seriesList_1 = (e_1 = void 0, __values(seriesList)), seriesList_1_1 = seriesList_1.next(); !seriesList_1_1.done; seriesList_1_1 = seriesList_1.next()) {
var series = seriesList_1_1.value;
series.source.cancel('request canceled');
series.abortController && series.abortController.abort();
}
} catch (e_1_1) {
e_1 = {
error: e_1_1
};
} finally {
try {
if (seriesList_1_1 && !seriesList_1_1.done && (_a = seriesList_1.return)) _a.call(seriesList_1);
} finally {
if (e_1) throw e_1.error;
}
}
this.waiting[url] = [];
}
}
};
/**
* Waiting to resolve the series 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>
*/
Serializer.prototype.wait = function (key, promiseKey) {
return __awaiter(this, void 0, void 0, function () {
var seriesList, index;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.orderly) return [2 /*return*/, Promise.resolve()];
seriesList = this.waiting[key] || [];
index = seriesList.findIndex(function (item) {
return item.promiseKey === promiseKey;
});
_b.label = 1;
case 1:
if (!(index > 0)) return [3 /*break*/, 7];
index--;
if (!(seriesList[index] && seriesList[index].promiseKey !== promiseKey)) return [3 /*break*/, 6];
_b.label = 2;
case 2:
_b.trys.push([2, 4,, 5]);
return [4 /*yield*/, seriesList[index].promise
// await seriesList.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:
seriesList.splice(index, 1);
_b.label = 6;
case 6:
return [3 /*break*/, 1];
case 7:
return [2 /*return*/];
}
});
});
};
/**
* set series to waiting list
*
* @param key - the key of waiting line, usually to be the request url
* @param series - waiting object
*/
Serializer.prototype.add = function (key, series) {
if (!(key in this.waiting)) this.waiting[key] = [];
this.waiting[key].push(series);
};
return Serializer;
}();
/**
* axios serializer wrapper function
*
* @param instance - axios or axios instance
* @param options - serializer options
* @return - axios instance with serializer feature
*/
function axiosSeries(instance, options) {
var serializer = new Serializer(instance, options);
function axiosWithSeries(url, config) {
var _a;
if (typeof url !== 'string') {
config = url;
} else {
config !== null && config !== void 0 ? config : config = {};
(_a = config.url) !== null && _a !== void 0 ? _a : config.url = url;
}
return serializer.request(config);
}
// axiosWithSeries.defaults = instance.defaults
// axiosWithSeries.interceptors = instance.interceptors
// axiosWithSeries.getUri = instance.getUri
// axiosWithSeries.request = instance.request
// axiosWithSeries.get = instance.get
// axiosWithSeries.delete = instance.delete
// axiosWithSeries.head = instance.head
// axiosWithSeries.options = instance.options
// axiosWithSeries.post = instance.post
// axiosWithSeries.put = instance.put
// axiosWithSeries.patch = instance.patch
// axiosWithSeries.postForm = instance.postForm
// axiosWithSeries.putForm = instance.putForm
// axiosWithSeries.patchForm = instance.patchForm
// axiosWithSeries.create = instance.create
// not in axios instance
// axiosWithSeries.Cancel = instance.Cancel
// axiosWithSeries.CancelToken = instance.CancelToken
// axiosWithSeries.Axios = instance.Axios
// axiosWithSeries.VERSION = instance.VERSION
// axiosWithSeries.isCancel = instance.isCancel
// axiosWithSeries.all = instance.all
// axiosWithSeries.spread = instance.spread
// axiosWithSeries.isAxiosError = instance.isAxiosError
/**
* all waiting series
*/
axiosWithSeries.series = serializer.waiting;
/**
* clear all series
*/
axiosWithSeries.clear = function () {
// clear all
serializer.clear();
};
return axiosWithSeries;
}
return axiosSeries;
})(axios);