@cloudcome/utils-core
Version:
cloudcome core utils
180 lines (179 loc) • 4.97 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const _function = require("./function.cjs");
class AsyncQueue {
/**
* 创建一个异步任务队列
* @param asyncFns - 要执行的异步函数数组
* @param options - 队列配置选项
*/
constructor(asyncFns, options) {
this.options = options;
asyncFns.forEach((afn, idx) => {
this.#add("push", afn);
});
}
#tasks = [];
#length = 0;
get length() {
return this.#length;
}
get limit() {
return this.options?.limit || 0;
}
#add(method, afn, pwr) {
this.#tasks[method]({
idx: this.#length++,
afn,
pwr
});
}
#addAndRun(method, afn) {
if (this.#stopLength >= 0) {
throw new Error("异步队列已被终止,无法添加新的任务");
}
const pwr = Promise.withResolvers();
this.#add(method, afn, pwr);
if (this.#startPwr && this.#running === 0) {
this.#run();
}
return pwr.promise;
}
async push(afn) {
return this.#addAndRun("push", afn);
}
async unshift(afn) {
return this.#addAndRun("unshift", afn);
}
#startResolved = 0;
#startRejected = 0;
get startSettled() {
return this.#startResolved === this.#startLength || this.#startRejected > 0;
}
#startResults = [];
#startPwr = null;
#startLength = 0;
/**
* 启动队列中的任务执行
* @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组
*/
async start() {
if (this.#startPwr) return this.#startPwr.promise;
this.#startLength = this.#length;
this.#startPwr = Promise.withResolvers();
if (this.#startLength === 0) {
this.#startPwr.resolve([]);
} else {
this.#run();
}
return this.#startPwr.promise;
}
#running = 0;
#run() {
while (this.limit === 0 || this.#running < this.limit) {
const task = this.#tasks.shift();
if (!task) break;
this.#running++;
task.afn().then((result) => {
this.#running--;
task.pwr?.resolve(result);
if (task.idx < this.#startLength) {
this.#startResults[task.idx] = result;
this.#startResolved++;
}
if (this.#startResolved === this.#startLength) {
this.#startPwr?.resolve(this.#startResults);
}
this.#stopResults[task.idx] = result;
this.#stopResolved++;
if (this.#stopResolved === this.#stopLength) {
this.#stopPwr?.resolve(this.#stopResults);
} else {
this.#run();
}
}).catch((reason) => {
this.#running--;
task.pwr?.reject(reason);
if (task.idx < this.#startLength) {
this.#startRejected++;
this.#startPwr?.reject(reason);
}
if (this.#stopLength > 0) {
this.#stopRejected++;
this.#stopPwr?.reject(reason);
}
});
}
}
#stopResolved = 0;
#stopRejected = 0;
get stopSettled() {
return this.#stopResolved === this.#stopLength || this.#stopRejected > 0;
}
#stopLength = -1;
#stopResults = [];
#stopPwr = null;
/**
* 终止队列中的任务执行,终止队列后不再可以追加异步任务
* @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组
*/
async stop() {
if (this.#stopPwr) {
return this.#stopPwr.promise;
}
this.#stopLength = this.#length;
this.#stopPwr = Promise.withResolvers();
if (this.#stopLength === 0) {
this.#stopPwr.resolve([]);
} else {
this.#run();
}
return this.#stopPwr.promise;
}
}
function asyncLimit(asyncFns, limit) {
const aq = new AsyncQueue(asyncFns, { limit });
return aq.start();
}
function asyncShared(af, options) {
let executedPromise;
let executing = false;
let executingInputs;
let executedTime = 0;
const _sharedAf = async (from, ...inputs) => {
executingInputs = inputs;
if (executing && executedPromise) {
return executedPromise;
}
if (executedPromise && Date.now() - executedTime < (options?.maxAge || 0)) {
return executedPromise;
}
executing = true;
options?.onExecute?.(...executingInputs);
executedPromise = af(...executingInputs);
executingInputs = void 0;
executedPromise.then((res) => {
options?.onSuccess?.(res);
}).catch((err) => {
options?.onError?.(err);
}).finally(() => {
executing = false;
executedTime = Date.now();
options?.onFinally?.();
if (executingInputs && options?.trailing) {
_sharedAf("trailing", ...executingInputs);
}
});
return executedPromise;
};
return function sharedAf(...inputs) {
options?.onTrigger?.(...inputs);
const p = _sharedAf("trigger", ...inputs);
p.catch(_function.fnNoop);
return p;
};
}
exports.AsyncQueue = AsyncQueue;
exports.asyncLimit = asyncLimit;
exports.asyncShared = asyncShared;
//# sourceMappingURL=async.cjs.map