@utilslib/core/DependencyManager
DependencyManager
函数签名
typescript
function DependencyManager() { ... }点击查看源码
js
/**
* 将值或值数组转换为数组。
*
* @type {<T>(value: T | T[]) => T[]}
* @param {T | T[]} value - 要转换的值或值数组。
* @returns {T[]} 转换后的数组。
*/
function toArray(value) {
return Array.isArray(value) ? value : [value];
}
/**
* 函数包装式依赖管理器
* 通过包装函数的方式管理依赖关系,确保在执行某个操作前所需的依赖都已完成
*/
export class DependencyManager {
/**
* 存储依赖状态的Map
* @private
*/
dependencies;
/**
* 存储依赖完成的Promise resolve函数的Map
* @private
*/
resolvers;
/**
* 创建依赖管理器实例
*/
constructor() {
this.dependencies = new Map();
this.resolvers = new Map();
}
/**
* 创建依赖提供者函数,执行后自动标记依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称,用于标识该依赖
* @param {AnyFunction} fn - 要包装的原始函数
* @returns {AsyncFunction<T, R>} 包装后的异步函数,执行完成后会自动标记依赖完成
*/
createProvider(depName, fn) {
return this._createProviderWrapper(depName, fn);
}
/**
* 立即执行依赖提供者函数,执行后自动标记依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称,用于标识该依赖
* @param {AnyFunction} fn - 要执行的原始函数
* @param {...T} args - 函数参数
* @returns {Promise<R>} 函数执行结果,执行完成后会自动标记依赖完成
*/
async provider(depName, fn, ...args) {
const wrapper = this._createProviderWrapper(depName, fn);
return wrapper(...args);
}
/**
* 创建等待依赖执行函数,执行前等待指定依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string | string[]} requiredDeps - 需要等待的依赖名称或依赖名称数组
* @param {AnyFunction} fn - 要包装的原始函数
* @param {DependencyOptions} [options={}] - 配置选项
* @returns {AsyncFunction<T, R>} 包装后的异步函数,会在依赖满足后执行
*/
createAwaitDepExec(requiredDeps, fn, options = {}) {
return this._createAwaitDepExecWrapper(requiredDeps, fn, options);
}
async awaitDepExec(requiredDeps, fn, optionsOrFirstArg, ...restArgs) {
let options = {};
let args;
// 判断第三个参数是否为选项对象
if (
optionsOrFirstArg !== undefined &&
typeof optionsOrFirstArg === "object" &&
optionsOrFirstArg !== null &&
"timeout" in optionsOrFirstArg
) {
options = optionsOrFirstArg;
args = restArgs;
} else {
args = [optionsOrFirstArg, ...restArgs];
}
const wrapper = this._createAwaitDepExecWrapper(requiredDeps, fn, options);
return wrapper(...args);
}
/**
* 检查指定依赖是否已完成
*
* @param {string} depName - 依赖名称
* @returns {boolean} 如果依赖已完成返回true,否则返回false
*/
isComplete(depName) {
return this.dependencies.get(depName) === true;
}
/**
* 手动标记依赖完成(用于非函数依赖或外部触发)
*
* @param {string} depName - 要标记完成的依赖名称
* @returns {DependencyManager} 返回当前实例,支持链式调用
*/
complete(depName) {
this._complete(depName);
return this;
}
/**
* 等待指定依赖完成
*
* @param {string | string[]} deps - 要等待的依赖名称或依赖名称数组
* @param {number} [timeout] - 可选的超时时间(毫秒)
* @returns {Promise<void>} 当所有指定依赖完成时resolve的Promise
* @throws {Error} 当超时时抛出错误
*/
async waitFor(deps, timeout) {
const depArray = Array.isArray(deps) ? deps : [deps];
return this._waitForAll(depArray, timeout);
}
/**
* 获取所有依赖的当前状态
*
* @returns {DependencyStatus} 包含所有依赖名称和完成状态的对象
*/
getStatus() {
const status = {};
for (const [key, value] of this.dependencies.entries()) {
if (!key.endsWith("_promise")) {
status[key] = value;
}
}
return status;
}
/**
* 重置所有依赖状态,清空所有已注册的依赖
*
* @returns {DependencyManager} 返回当前实例,支持链式调用
*/
reset() {
this.dependencies.clear();
this.resolvers.clear();
return this;
}
/**
* 创建依赖提供者包装函数的通用逻辑
*
* @private
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称
* @param {AnyFunction} fn - 要包装的原始函数
* @returns {AsyncFunction<T, R>} 包装后的异步函数
*/
_createProviderWrapper(depName, fn) {
this._register(depName);
return async (...args) => {
try {
const result = await fn(...args);
this._complete(depName);
return result;
} catch (error) {
this._complete(depName);
throw error;
}
};
}
/**
* 创建等待依赖执行包装函数的通用逻辑
*
* @private
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string | string[]} requiredDeps - 需要等待的依赖名称或依赖名称数组
* @param {AnyFunction} fn - 要包装的原始函数
* @param {DependencyOptions} options - 配置选项
* @returns {AsyncFunction<T, R>} 包装后的异步函数
*/
_createAwaitDepExecWrapper(requiredDeps, fn, options) {
const deps = toArray(requiredDeps);
deps.forEach((dep) => this._register(dep));
return async (...args) => {
await this._waitForAll(deps, options.timeout);
return await fn(...args);
};
}
/**
* 注册一个依赖项到管理器中
*
* @private
* @param {string} depName - 要注册的依赖名称
*/
_register(depName) {
if (this.dependencies.has(depName)) return;
this.dependencies.set(depName, false);
const promise = new Promise((resolve) => {
this.resolvers.set(depName, resolve);
});
this.dependencies.set(`${depName}_promise`, promise);
}
/**
* 标记指定依赖为已完成状态
*
* @private
* @param {string} depName - 要标记完成的依赖名称
*/
_complete(depName) {
if (!this.dependencies.has(depName)) return;
this.dependencies.set(depName, true);
const resolver = this.resolvers.get(depName);
if (resolver) {
resolver();
this.resolvers.delete(depName);
}
}
/**
* 等待所有指定的依赖完成
*
* @private
* @param {string[]} deps - 要等待的依赖名称数组
* @param {number} [timeout] - 可选的超时时间(毫秒)
* @returns {Promise<void>} 当所有依赖完成时resolve的Promise
* @throws {Error} 当超时时抛出错误
*/
async _waitForAll(deps, timeout) {
const promises = deps.map((dep) => {
if (this.isComplete(dep)) {
return Promise.resolve();
}
return this.dependencies.get(`${dep}_promise`);
});
const waitPromise = Promise.all(promises);
if (timeout) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`依赖等待超时 (${timeout}ms)`));
}, timeout);
});
await Promise.race([waitPromise, timeoutPromise]);
} else {
await waitPromise;
}
}
}ts
export type AnyFunction = (...args: any) => any;
/**
* 异步函数类型
*/
type AsyncFunction<T extends any[] = any[], R = any> = (
...args: T
) => Promise<R>;
/**
* 函数包装式依赖管理器选项接口
*/
interface DependencyOptions {
/** 超时时间(毫秒) */
timeout?: number;
}
/**
* 依赖状态类型
*/
type DependencyStatus = Record<string, boolean>;
/**
* 将值或值数组转换为数组。
*
* @type {<T>(value: T | T[]) => T[]}
* @param {T | T[]} value - 要转换的值或值数组。
* @returns {T[]} 转换后的数组。
*/
function toArray<T>(value: T | T[]): T[] {
return Array.isArray(value) ? value : [value];
}
/**
* 函数包装式依赖管理器
* 通过包装函数的方式管理依赖关系,确保在执行某个操作前所需的依赖都已完成
*/
export class DependencyManager {
/**
* 存储依赖状态的Map
* @private
*/
private readonly dependencies: Map<string, boolean>;
/**
* 存储依赖完成的Promise resolve函数的Map
* @private
*/
private readonly resolvers: Map<string, () => void>;
/**
* 创建依赖管理器实例
*/
constructor() {
this.dependencies = new Map<string, boolean>();
this.resolvers = new Map<string, () => void>();
}
/**
* 创建依赖提供者函数,执行后自动标记依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称,用于标识该依赖
* @param {AnyFunction} fn - 要包装的原始函数
* @returns {AsyncFunction<T, R>} 包装后的异步函数,执行完成后会自动标记依赖完成
*/
createProvider<T extends any[] = any[], R = any>(
depName: string,
fn: AnyFunction,
): AsyncFunction<T, R> {
return this._createProviderWrapper(depName, fn);
}
/**
* 立即执行依赖提供者函数,执行后自动标记依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称,用于标识该依赖
* @param {AnyFunction} fn - 要执行的原始函数
* @param {...T} args - 函数参数
* @returns {Promise<R>} 函数执行结果,执行完成后会自动标记依赖完成
*/
async provider<T extends any[] = any[], R = any>(
depName: string,
fn: AnyFunction,
...args: T
): Promise<R> {
const wrapper = this._createProviderWrapper<T, R>(depName, fn);
return wrapper(...args);
}
/**
* 创建等待依赖执行函数,执行前等待指定依赖完成
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string | string[]} requiredDeps - 需要等待的依赖名称或依赖名称数组
* @param {AnyFunction} fn - 要包装的原始函数
* @param {DependencyOptions} [options={}] - 配置选项
* @returns {AsyncFunction<T, R>} 包装后的异步函数,会在依赖满足后执行
*/
createAwaitDepExec<T extends any[] = any[], R = any>(
requiredDeps: string | string[],
fn: AnyFunction,
options: DependencyOptions = {},
): AsyncFunction<T, R> {
return this._createAwaitDepExecWrapper(requiredDeps, fn, options);
}
/**
* 立即等待依赖并执行函数
*
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string | string[]} requiredDeps - 需要等待的依赖名称或依赖名称数组
* @param {AnyFunction} fn - 要执行的原始函数
* @param {DependencyOptions} options - 配置选项
* @param {...T} args - 函数参数
* @returns {Promise<R>} 函数执行结果,会在依赖满足后执行
*/
async awaitDepExec<T extends any[] = any[], R = any>(
requiredDeps: string | string[],
fn: AnyFunction,
options: DependencyOptions,
...args: T
): Promise<R>;
async awaitDepExec<T extends any[] = any[], R = any>(
requiredDeps: string | string[],
fn: AnyFunction,
...args: T
): Promise<R>;
async awaitDepExec<T extends any[] = any[], R = any>(
requiredDeps: string | string[],
fn: AnyFunction,
optionsOrFirstArg?: DependencyOptions | T[0],
...restArgs: T extends [any, ...infer Rest] ? Rest : never[]
): Promise<R> {
let options: DependencyOptions = {};
let args: T;
// 判断第三个参数是否为选项对象
if (
optionsOrFirstArg !== undefined &&
typeof optionsOrFirstArg === "object" &&
optionsOrFirstArg !== null &&
"timeout" in optionsOrFirstArg
) {
options = optionsOrFirstArg as DependencyOptions;
args = restArgs as unknown as T;
} else {
args = [optionsOrFirstArg, ...restArgs] as T;
}
const wrapper = this._createAwaitDepExecWrapper<T, R>(
requiredDeps,
fn,
options,
);
return wrapper(...args);
}
/**
* 检查指定依赖是否已完成
*
* @param {string} depName - 依赖名称
* @returns {boolean} 如果依赖已完成返回true,否则返回false
*/
isComplete(depName: string): boolean {
return this.dependencies.get(depName) === true;
}
/**
* 手动标记依赖完成(用于非函数依赖或外部触发)
*
* @param {string} depName - 要标记完成的依赖名称
* @returns {DependencyManager} 返回当前实例,支持链式调用
*/
complete(depName: string): DependencyManager {
this._complete(depName);
return this;
}
/**
* 等待指定依赖完成
*
* @param {string | string[]} deps - 要等待的依赖名称或依赖名称数组
* @param {number} [timeout] - 可选的超时时间(毫秒)
* @returns {Promise<void>} 当所有指定依赖完成时resolve的Promise
* @throws {Error} 当超时时抛出错误
*/
async waitFor(deps: string | string[], timeout?: number): Promise<void> {
const depArray = Array.isArray(deps) ? deps : [deps];
return this._waitForAll(depArray, timeout);
}
/**
* 获取所有依赖的当前状态
*
* @returns {DependencyStatus} 包含所有依赖名称和完成状态的对象
*/
getStatus(): DependencyStatus {
const status: DependencyStatus = {};
for (const [key, value] of this.dependencies.entries()) {
if (!key.endsWith("_promise")) {
status[key] = value;
}
}
return status;
}
/**
* 重置所有依赖状态,清空所有已注册的依赖
*
* @returns {DependencyManager} 返回当前实例,支持链式调用
*/
reset(): DependencyManager {
this.dependencies.clear();
this.resolvers.clear();
return this;
}
/**
* 创建依赖提供者包装函数的通用逻辑
*
* @private
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string} depName - 依赖名称
* @param {AnyFunction} fn - 要包装的原始函数
* @returns {AsyncFunction<T, R>} 包装后的异步函数
*/
private _createProviderWrapper<T extends any[] = any[], R = any>(
depName: string,
fn: AnyFunction,
): AsyncFunction<T, R> {
this._register(depName);
return async (...args: T): Promise<R> => {
try {
const result = await fn(...args);
this._complete(depName);
return result;
} catch (error) {
this._complete(depName);
throw error;
}
};
}
/**
* 创建等待依赖执行包装函数的通用逻辑
*
* @private
* @template T - 函数参数类型数组
* @template R - 函数返回值类型
* @param {string | string[]} requiredDeps - 需要等待的依赖名称或依赖名称数组
* @param {AnyFunction} fn - 要包装的原始函数
* @param {DependencyOptions} options - 配置选项
* @returns {AsyncFunction<T, R>} 包装后的异步函数
*/
private _createAwaitDepExecWrapper<T extends any[] = any[], R = any>(
requiredDeps: string | string[],
fn: AnyFunction,
options: DependencyOptions,
): AsyncFunction<T, R> {
const deps = toArray(requiredDeps);
deps.forEach((dep) => this._register(dep));
return async (...args: T): Promise<R> => {
await this._waitForAll(deps, options.timeout);
return await fn(...args);
};
}
/**
* 注册一个依赖项到管理器中
*
* @private
* @param {string} depName - 要注册的依赖名称
*/
private _register(depName: string): void {
if (this.dependencies.has(depName)) return;
this.dependencies.set(depName, false);
const promise = new Promise<void>((resolve) => {
this.resolvers.set(depName, resolve);
});
this.dependencies.set(`${depName}_promise`, promise as any);
}
/**
* 标记指定依赖为已完成状态
*
* @private
* @param {string} depName - 要标记完成的依赖名称
*/
private _complete(depName: string): void {
if (!this.dependencies.has(depName)) return;
this.dependencies.set(depName, true);
const resolver = this.resolvers.get(depName);
if (resolver) {
resolver();
this.resolvers.delete(depName);
}
}
/**
* 等待所有指定的依赖完成
*
* @private
* @param {string[]} deps - 要等待的依赖名称数组
* @param {number} [timeout] - 可选的超时时间(毫秒)
* @returns {Promise<void>} 当所有依赖完成时resolve的Promise
* @throws {Error} 当超时时抛出错误
*/
private async _waitForAll(deps: string[], timeout?: number): Promise<void> {
const promises = deps.map((dep) => {
if (this.isComplete(dep)) {
return Promise.resolve();
}
return this.dependencies.get(`${dep}_promise`);
});
const waitPromise = Promise.all(promises);
if (timeout) {
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(new Error(`依赖等待超时 (${timeout}ms)`));
}, timeout);
});
await Promise.race([waitPromise, timeoutPromise]);
} else {
await waitPromise;
}
}
}如有错误,请提交issue :::