UNPKG

@cloudcome/utils-core

Version:
180 lines (179 loc) 4.97 kB
"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