async-pond
Version:
一个使用 promise 来解决并发异步控制的方案,无任何依赖
195 lines (185 loc) • 9.38 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global["async-pond"] = factory());
})(this, (function () { 'use strict';
/*! *****************************************************************************
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());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { 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 (_) 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 isObject(obj) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
function to(promise, errorExt) {
return promise
.then(function (data) { return [null, data]; })
.catch(function (err) {
if (errorExt) {
Object.assign(err, errorExt);
}
return [err, undefined];
});
}
var AsyncPoolPro = /** @class */ (function () {
function AsyncPoolPro(poolLimit, options) {
this.poolLimit = 3;
this.promisePool = [];
this.poolControlers = [];
this.poolIndex = 0;
this.whileControl = false;
this.promiseGroups = {};
this.options = {
isReTry: false,
retryNum: 3,
};
this.promisePool = []; // 存储所有的异步任务,且当前异步任务均为pending态
this.poolControlers = []; //异步请求的参数
this.poolLimit = poolLimit || 3; //并发限制数量
this.poolIndex = 0;
this.whileControl = false;
if (isObject(options)) {
Object.assign(this.options, options);
}
}
AsyncPoolPro.prototype.push = function (poolParams, iteratorFn) {
var _a;
var _this = this;
var flag = Symbol();
var poolControlers = (Array.isArray(poolParams) ? poolParams : [poolParams]).map(function (i) { return ({
iteratorFn: iteratorFn,
param: i,
flag: flag,
}); });
(_a = this.poolControlers).push.apply(_a, poolControlers);
this.promiseGroups[flag] = {
length: poolControlers.length,
finishNum: 0,
pendingPromises: [],
};
this.asyncPool(this.promisePool.length === 0);
return new Promise(function (resolve) {
_this.promiseGroups[flag].resolve = resolve;
});
};
/**
* 延迟生成Promise异步
* @param poolControlers 异步请求的参数
*/
AsyncPoolPro.prototype.generatorPromise = function (poolControlers) {
var _this = this;
if (poolControlers === void 0) { poolControlers = this.poolControlers; }
var _a = poolControlers[this.poolIndex], iteratorFn = _a.iteratorFn, param = _a.param, flag = _a.flag;
var group = this.promiseGroups[flag];
var p = Promise.resolve()
.then(function () {
return iteratorFn(param);
})
.finally(function () {
var finishPromiseIndex = _this.promisePool.indexOf(p);
_this.promisePool.splice(finishPromiseIndex, 1);
_this.poolControlers.splice(finishPromiseIndex, 1);
_this.poolIndex--;
group.finishNum++;
if (group.length === group.finishNum) {
// 当前组都结束pending后,执行group
group.resolve &&
group.resolve(Promise.allSettled(group.pendingPromises));
}
});
group.pendingPromises.push(p);
this.promisePool.push(p); // 保存新的异步任务
this.options.afterInitSingleAsync &&
this.options.afterInitSingleAsync(this.promisePool);
if (this.promisePool.length >= this.poolLimit) {
return Promise.race(this.promisePool); // 等待较快的任务执行完成
}
};
/**
* 并发控制逻辑
* @param {boolean} isInit 是否初始化控制?
*/
AsyncPoolPro.prototype.asyncPool = function (isInit) {
return __awaiter(this, void 0, void 0, function () {
var flag, racePromise;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(isInit || this.whileControl)) return [3 /*break*/, 5];
this.whileControl = false;
flag = this.poolControlers[this.poolIndex].flag;
this.promiseGroups[flag];
_a.label = 1;
case 1:
if (!(this.poolIndex < this.poolControlers.length)) return [3 /*break*/, 4];
racePromise = this.generatorPromise();
if (!racePromise) return [3 /*break*/, 3];
return [4 /*yield*/, to(racePromise)];
case 2:
_a.sent();
_a.label = 3;
case 3:
this.poolIndex++;
return [3 /*break*/, 1];
case 4:
//while循环结束标识
this.whileControl = true;
_a.label = 5;
case 5: return [2 /*return*/];
}
});
});
};
return AsyncPoolPro;
}());
return AsyncPoolPro;
}));
//# sourceMappingURL=async-pond.umd.js.map