@lgd-utils/request-queue
Version:
A front-end request-queue tool
484 lines (387 loc) • 17.4 kB
JavaScript
'use strict';
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
Object.defineProperty(exports, '__esModule', {
value: true
});
var lodashBind = require('lodash/bind');
var lodashIsBoolean = require('lodash/isBoolean');
var lodashIsFunction = require('lodash/isFunction');
var lodashIsNumber = require('lodash/isNumber');
var lodashIsPlainObject = require('lodash/isPlainObject');
var lodashIsString = require('lodash/isString');
var lodashOmit = require('lodash/omit');
function _interopDefaultLegacy(e) {
return e && _typeof(e) === 'object' && 'default' in e ? e['default'] : e;
}
var lodashBind__default = /*#__PURE__*/_interopDefaultLegacy(lodashBind);
var lodashIsBoolean__default = /*#__PURE__*/_interopDefaultLegacy(lodashIsBoolean);
var lodashIsFunction__default = /*#__PURE__*/_interopDefaultLegacy(lodashIsFunction);
var lodashIsNumber__default = /*#__PURE__*/_interopDefaultLegacy(lodashIsNumber);
var lodashIsPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(lodashIsPlainObject);
var lodashIsString__default = /*#__PURE__*/_interopDefaultLegacy(lodashIsString);
var lodashOmit__default = /*#__PURE__*/_interopDefaultLegacy(lodashOmit);
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
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());
});
}
/*
* @Author: shiconghua
* @Alias: LGD.HuaFEEng
* @Date: 2021-06-26 23:25:35
* @LastEditTime: 2021-12-20 19:31:09
* @LastEditors: shiconghua
* @Description: file content
* @FilePath: \lgd-utils\packages\request-queue\src\index.ts
*/
// 请求队列,控制请求并发
var RequestQueue = /*#__PURE__*/function () {
function RequestQueue() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
completeHooks = _ref.completeHooks,
destroyWhenError = _ref.destroyWhenError,
destroyWhenErrorHooks = _ref.destroyWhenErrorHooks,
enableAwaitWhenRetry = _ref.enableAwaitWhenRetry,
enableContinueRetryWhenStop = _ref.enableContinueRetryWhenStop,
limit = _ref.limit,
maxConcurrent = _ref.maxConcurrent,
onAlways = _ref.onAlways,
onError = _ref.onError,
onSuccess = _ref.onSuccess,
requestAdapter = _ref.requestAdapter,
requestAdapterApiConfig = _ref.requestAdapterApiConfig,
requestList = _ref.requestList,
retry = _ref.retry,
retryTimes = _ref.retryTimes;
_classCallCheck(this, RequestQueue);
// List特征请求完成总数
this.complete = 0; // 实例是否销毁
this.destroyed = false; // 失败的Key
this.errorKeys = []; // List特征请求完成进度,表示当前位置
this.progress = 0; // 请求结果
this.requestResult = []; // 总请求数,所有发送的请求总数
this.requests = 0; // 是否正在运行
this.running = false; // 成功的key
this.successKeys = []; // List特征请求总数
this.total = 0;
var noop = function noop() {
return void 0;
};
this.completeHooks = Array.isArray(completeHooks) ? completeHooks.filter(lodashIsFunction__default) : lodashIsFunction__default(completeHooks) ? [completeHooks] : [];
this.destroyWhenError = lodashIsBoolean__default(destroyWhenError) ? destroyWhenError : false;
this.destroyWhenErrorHooks = Array.isArray(destroyWhenErrorHooks) ? destroyWhenErrorHooks.filter(lodashIsFunction__default) : lodashIsFunction__default(destroyWhenErrorHooks) ? [destroyWhenErrorHooks] : [];
this.enableAwaitWhenRetry = lodashIsBoolean__default(enableAwaitWhenRetry) ? enableAwaitWhenRetry : false;
this.enableContinueRetryWhenStop = lodashIsBoolean__default(enableContinueRetryWhenStop) ? enableContinueRetryWhenStop : true;
this.maxConcurrent = lodashIsNumber__default(maxConcurrent) ? maxConcurrent : lodashIsNumber__default(limit) ? limit : 6;
this.onAlways = onAlways || noop;
this.onError = onError || noop;
this.onSuccess = onSuccess || noop;
this.requestAdapter = requestAdapter || function (apiConfig) {
return Promise.resolve(apiConfig);
};
this.requestAdapterApiConfig = requestAdapterApiConfig || {};
this.requestList = _toConsumableArray(Array.isArray(requestList) ? requestList : []);
this.retryTimes = lodashIsNumber__default(retryTimes) ? retryTimes : lodashIsNumber__default(retry) ? retry : 1;
this.total = this.requestList.length;
this._resolve = noop;
this._reject = noop;
}
_createClass(RequestQueue, [{
key: "_assertPromisify",
value: function _assertPromisify() {
if (this.completeHooks.length || this.destroyWhenErrorHooks.length) return false;
return true;
}
}, {
key: "_concurrent",
value: function _concurrent(limit) {
var _this = this;
if (this._assertDisabled()) return this; // 当请求队列为空时,直接done
if (this.progress === 0 && this.complete === 0 && this.total === 0 && this.requests === 0) {
if (this._assertPromisify()) {
this._resolve([]);
} else {
this.completeHooks.forEach(function (fn) {
return fn([], _this.progress);
});
}
return this;
}
if (limit === void 0) limit = this.maxConcurrent;
while (limit--) {
this._next();
}
return this;
}
}, {
key: "_assertDisabled",
value: function _assertDisabled() {
if (this.destroyed || !this.running) return true;
return false;
}
}, {
key: "_next",
value: function _next() {
var curProgress = this.progress;
if (curProgress >= this.total || this._assertDisabled()) return this;
this.progress++;
this._runRequestItem(curProgress);
}
}, {
key: "_runRequestItem",
value: function _runRequestItem(curProgress, item) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var _this2 = this;
var requestItem, _requestItem, res, data;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!this.destroyed) {
_context.next = 2;
break;
}
return _context.abrupt("return", this);
case 2:
requestItem = item || this._getRequestItem();
if (requestItem) {
_context.next = 5;
break;
}
return _context.abrupt("return", this);
case 5:
_requestItem = requestItem;
_context.prev = 6;
_context.next = 9;
return Promise.resolve(requestItem.request());
case 9:
res = _context.sent;
this.requestResult[curProgress] = {
key: curProgress,
type: 'SUCCESS',
requestItem: _requestItem,
data: this.onSuccess && this.onSuccess(res, curProgress) || res,
isRequestQueue: true
};
this.successKeys.push(_requestItem && _requestItem._key !== void 0 ? {
key: _requestItem._key,
index: curProgress
} : curProgress);
this.complete++;
if (this.complete < this.total) {
this._next();
}
_context.next = 33;
break;
case 16:
_context.prev = 16;
_context.t0 = _context["catch"](6);
if (!(_requestItem.retryTimes > 0 && (this.running || !this.running && this.enableContinueRetryWhenStop))) {
_context.next = 28;
break;
}
_requestItem.retryTimes--;
if (!this.enableAwaitWhenRetry) {
_context.next = 25;
break;
}
_context.next = 23;
return this._runRequestItem(curProgress, requestItem);
case 23:
_context.next = 26;
break;
case 25:
this._runRequestItem(curProgress, requestItem);
case 26:
_context.next = 33;
break;
case 28:
data = this.onError && this.onError(_context.t0, curProgress) || _context.t0;
this.requestResult[curProgress] = {
key: curProgress,
type: 'ERROR',
requestItem: _requestItem,
data: data,
isRequestQueue: true
};
this.errorKeys.push(_requestItem && _requestItem._key !== void 0 ? {
key: _requestItem._key,
index: curProgress
} : curProgress);
this.complete++;
if (this.destroyWhenError) {
if (this._assertPromisify()) {
this._reject(this.requestResult[curProgress]);
} else {
this.destroyWhenErrorHooks.forEach(function (fn) {
return fn(data, curProgress, 'ERROR');
});
}
this.destroy();
} else {
if (this.complete < this.total) {
this._next();
}
}
case 33:
_context.prev = 33;
this.requests++;
if (this.complete >= this.total && !this.destroyed) {
if (this._assertPromisify()) {
this._resolve(_toConsumableArray(this.requestResult));
} else {
this.completeHooks.forEach(function (fn) {
return fn(_toConsumableArray(_this2.requestResult), curProgress);
});
}
this.destroy();
}
return _context.finish(33);
case 37:
case "end":
return _context.stop();
}
}
}, _callee, this, [[6, 16, 33, 37]]);
}));
}
}, {
key: "_getRequestItem",
value: function _getRequestItem() {
if (this._assertDisabled()) return null;
var request = this.requestList.shift();
if (!request) return request;
if (lodashIsFunction__default(request)) {
return {
request: request,
retryTimes: this.retryTimes,
originalRetryTimes: this.retryTimes
};
}
if (lodashIsPlainObject__default(request)) {
var _request = lodashIsFunction__default(request._request) ? request._request : null;
var _customData = lodashIsPlainObject__default(request._customData) ? request._customData : {};
var retryTimes = _customData.retry === void 0 ? this.retryTimes : _customData.retry;
return Object.assign({
request: _request || lodashBind__default(function () {
return this.requestAdapter(Object.assign({}, lodashIsPlainObject__default(this.requestAdapterApiConfig) ? this.requestAdapterApiConfig : {
url: this.requestAdapterApiConfig
}, lodashOmit__default(request, ['_request', '_customData'])));
}, this),
retryTimes: retryTimes,
originalRetryTimes: retryTimes
}, _customData);
}
if (lodashIsString__default(request)) {
return {
request: lodashBind__default(function () {
return this.requestAdapter(lodashIsString__default(this.requestAdapterApiConfig) ? request : Object.assign({}, this.requestAdapterApiConfig, {
url: request
}));
}, this),
retryTimes: this.retryTimes,
originalRetryTimes: this.retryTimes
};
}
return {
request: lodashBind__default(function () {
return Promise.resolve(request);
}, this),
retryTimes: this.retryTimes,
originalRetryTimes: this.retryTimes
};
}
}, {
key: "add",
value: function add(request) {
if (this.destroyed || request === void 0) return this;
this.requestList.push(request);
this.total++;
return this;
}
}, {
key: "start",
value: function start(onComplete, onDestroyWhenError) {
var _this3 = this;
if (this.destroyed || this.running) return this;
this.running = true;
if (lodashIsFunction__default(onComplete)) this.completeHooks.push(onComplete);
if (lodashIsFunction__default(onDestroyWhenError)) this.destroyWhenErrorHooks.push(onDestroyWhenError);
if (this._assertPromisify()) {
return new Promise(function (resolve, reject) {
_this3._resolve = resolve;
_this3._reject = reject;
_this3._concurrent();
});
}
return this._concurrent();
}
}, {
key: "stop",
value: function stop() {
if (this._assertDisabled()) return this;
this.running = false;
return this;
}
}, {
key: "restart",
value: function restart() {
if (this.destroyed || this.running) return this;
this.running = true;
return this._concurrent();
}
}, {
key: "destroy",
value: function destroy() {
if (this.destroyed) return this;
this.running = false;
this.destroyed = true;
return this;
}
}]);
return RequestQueue;
}();
exports['default'] = RequestQueue;