UNPKG

worker-tls

Version:

worker-tls 提供了 动态Worker 功能 和 其它一些 Worker 场景下有用的工具集;让开发者可以像调用对象方法一样动态地调用Worker中的方法,也可以随时地往 Worker 中动态地添加函数 等等。

783 lines (731 loc) 23.6 kB
/** * worker 工具 * * @remarks * worker-tls 提供了关于worker 的一些工具,用于便捷地使用 worker * * @packageDocumentation */ import type { AnyFunction } from 'type-tls'; import dynamicWorkerCodeString from '/temp/dynamicWorkerMain.iife.js?raw'; import listenMessages_Dep from '/temp/listenMessages_Dep.iife.js?raw'; import type { Optional } from 'type-tls'; import type { PickMethod } from 'type-tls'; /** * 转为异步的命令 * @remarks * 函数的入参不变,返回参数都变为解决值为对应类型的 Promise * 其它非函数的值都变为返回解决值为对应类型的 Promise 的函数 */ export declare type AsyncCMD<Value> = Value extends AnyFunction ? AsyncFun<Value> : (() => Promise<Awaited<Value>>); /** * 把函数转为异步函数 */ export declare type AsyncFun<Fun extends (...args: any) => any> = GetExecFunResultData<Fun> extends ReadableStream ? (...args: AsyncFunArgs<Fun>) => GetExecFunResultData<Fun> : (...args: AsyncFunArgs<Fun>) => Promise<GetExecFunResultData<Fun>>; /** * 异步函数的参数类型 */ export declare type AsyncFunArgs<Fun extends (...args: any) => any> = Parameters<Fun> | [CallOptions<Parameters<Fun>>]; /** * 函数的调用选项 * * @remarks * 用于设置 transfer */ export declare interface CallOptions<Args extends any[] = any[]> { /** * 给worker 里对应的函数传递的参数 */ args: Args; /** * 设置将参数传送给 worker 时可转移的数据 */ transfer: Transferable[]; } /** * 代码片段 */ export declare type CodePart = Fun | BlobPart; /** * 代码块列表 */ export declare type CodePartList = (CodePart | INamedFunction | INamedFunctionMap)[]; /** * 代码块选项的综合定义 */ export declare type CodePartOptions = CodePartList | INamedFunctionMap; /** * 打包 options 中的代码并转成 BlobPart[] * @remarks * 传入的所有的代码块最终会被分为以下几类: * * 1. `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 Worker 中的 `globalThis` 上,其中 名字会作为 属性名字; * * 2. `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 Worker 启动时作为顶层代码被立即执行; * * 3. `message` 监听器会在 Worker 中接收 `message` 事件; * * @param options * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码(环境代码) * @returns */ export declare function createBlobParts(options: IWorkerCodes, noDep?: Optional<boolean>): BlobPart[]; /** * 创建动态 Worker * * @param worker - worker实例 * @param name - worker中运行的js文件的url * @param url - Worker 中所包含的初始代码 * @param code - Worker 中所包含的初始代码 * @param workerOptions - Worker 相关的选项 * @returns */ export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(noCode?: undefined | null, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorker<W>; export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(worker: W, name?: string): MembersToAsyncCMD<Members> & DynamicWorker<W>; export declare function createDynamicWorker<Members, W extends AbstractWorker = Worker>(url: string, workerOptions?: Optional<Omit<DynamicWorkerOptions<W>, "noDep">>): MembersToAsyncCMD<Members> & DynamicWorker<W>; export declare function createDynamicWorker<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(code: DynamicWorkerCodes<PickMethod<Members>>, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorker<W>; export declare function createDynamicWorker<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(codeOptions?: Optional<DynamicWorkerCodes<Members> | string | W>, workerOptions?: Optional<DynamicWorkerOptions<W> | string>): MembersToAsyncCMD<Members> & DynamicWorker<W>; /** * 创建动态 Worker 池 * * @param workerNum - Worker池 中 workder 的个数 * @param codeOptions - Worker 中所包含的初始代码 * @param workerOptions - Worker 相关的选项 * @returns */ export declare function createDynamicWorkerPool<Members extends Record<string | number, any>, W extends AbstractWorker = Worker>(workerNum: number, codeOptions?: Optional<IWorkerCodes | string>, workerOptions?: Optional<DynamicWorkerOptions<W>>): MembersToAsyncCMD<Members> & DynamicWorkerPool<W>; /** * 生成可用于创建动态 Worker 的 url * * @remarks * * {@inheritDoc ./stringify.ts#dynamicWorkerCodeString} * * @param codeOptions - 往 Worker 中注入代码的配置选项 * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码(环境代码) */ export declare function createDynamicWorkerURL(codeOptions?: Optional<IWorkerCodes>, noDep?: Optional<boolean>): string; /** * 通过代码构建 ObjectURL * @param codes * @param args - 对于立即调用的函数传的参数 * @returns */ export declare function createObjectURLByCodes(codes: CodePart[], args?: Optional<any[]>): string; /** * 将一组脚本内容构造成 ObjectURL * @param scripts - 脚本内容 * @param options - 选项 * @returns url字符串 */ export declare function createObjectURLByContents(scripts: BlobPart[], options?: BlobPropertyBag | null): string; /** * 创建Worker客户端的代理 * @param client * @returns */ export declare function createWorkerClientProxy<WClient extends WorkerClient<AbstractWorker>>(client: WClient): any; /** * 生成可用于创建 worker 的 url * @remarks * 打包 codeOptions 中的代码并生成可用于创建 worker 的 url * @param codeOptions - 往 Worker 中注入代码的配置选项 * @param noDep - 禁止包含 创建 Worker 时所需要的其它依赖代码(环境代码) * @returns */ export declare function createWorkerURL(codeOptions: IWorkerCodes, noDep?: Optional<boolean>): string; /** * 动态 Worker 给 Worker 扩展后的类型 */ export declare type DWorker<W extends AbstractWorker> = W & { /** * 当前正在执行的任务数 */ executingCount: number; /** * Worker的名字 */ name: string; /** * Worker所属的 WorkerClient 的id */ clientId: number; /** * Worker 本身的 id */ id: number; }; /** * 动态Worker * * @remarks * 动态 Worker 具备以下特点: * * - 往 Worker 中添加函数、全局变量 等 * * - 调用 Worker 中的任意全局函数 或 全局变量 * * - 像调用本地方法一样调用 Worker 里的方法 * * - 会自动给实例自身添加快捷命令 * * - 支持异步、流 * * - 支持异步和流互相嵌套 */ export declare class DynamicWorker<W extends AbstractWorker = Worker> extends WorkerClient<W> { /** * * @param worker 已创建好的 worker 实例 * @param name */ constructor(); constructor(worker: W, name?: string); constructor(url: string, workerOptions?: Optional<Omit<DynamicWorkerOptions<W>, "noDep">>); constructor(code: IWorkerCodes, workerOptions?: Optional<DynamicWorkerOptions<W>>); constructor(codeOrUrlOrWorker?: Optional<IWorkerCodes | string | W>, workerOptionsOrName?: Optional<DynamicWorkerOptions<W> | string>); /** * Worker 的实例 */ worker: DWorker<W>; /** * 正在执行中的任务数 */ get executingCount(): number; /** * 设置命令 * @remarks * 会在Worker中添加一条命令,并且也会在实例自身上添加一个快捷命令(快捷方法 或 快捷属性) * * @param cmd * @param name - 命令的命名;默认会取 `cmd.name` 作为名字;当 cmd 是字符串时,name 是必须的 * @param isProperty - 添加到实例自身的快捷命令是否作为属性;如果是 true,则会在实例自身上生成快捷属性 * @returns */ setCMD(cmd: string | AnyFunction, name?: Optional<string>, isProperty?: Optional<boolean>): Promise<boolean>; /** * 移除命令 * @remarks * 会将 Worker 中的命令 和 自己实例上的对应快捷方法都给移除 * @param name * @returns */ removeCMD(name: string): Promise<boolean>; } /** * 动态 Worker 的初始配置 code */ export declare type DynamicWorkerCodes<Methods extends INamedFunctionMap> = Omit<IWorkerCodes, "named"> & { named?: Optional<Methods | INamedFunctionList>; }; export { dynamicWorkerCodeString } /** * 从 worker 实例创建 动态 Worker 的选项 */ export declare interface DynamicWorkerFromInstOptions<W extends AbstractWorker = Worker> { /** * Worker 实例 */ worker: W; /** * worker 的名字 */ name?: string; } /** * 动态 Worker 的选项 */ export declare interface DynamicWorkerOptions<W extends AbstractWorker = Worker> { /** * 获取 Worker 实例的方法 * @defaultValue 默认会创建私有 Worker */ getWorker?: Optional<GetWorker<W>>; /** * worker 的名字 */ name?: string; /** * 是否是不自动添加 动态 worker 依赖的环境代码 * 如果明确指定为 true,则不会包含 动态 worker 依赖的环境代码 * @defaultValue true */ noDep?: boolean; } /** * 动态Worker池 */ export declare class DynamicWorkerPool<W extends AbstractWorker = Worker> extends WorkerClient<W> { /** * * @param workerNum - Worker池 中 workder 的个数 * @param codeOrUrl - code 选项 或 url * @param workerOptions - Worker 相关的选项 */ constructor(workerNum: number, codeOrUrl?: Optional<IWorkerCodes | string>, workerOptions?: Optional<DynamicWorkerOptions<W>>); /** * Worker 队列 */ readonly queue: SortQueue<DWorker<W>>; get worker(): DWorker<W>; get executingCount(): number; execStarted(worker: DWorker<W>, execRec: ExecRecord): void; execEnded(worker: DWorker<W>): void; /** * 在指定 worker 中的执行命令 * * @remarks * 当 worker 中成功执行,且 this 上没有对应的成员时,则会自动新增对应的成员方法 * * @param exec - 命令信息 * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker,而发当前环境将不再保有所有权。 * @returns */ execCMDOnWorker(worker: DWorker<W>, exec: Exec, transfer?: Transferable[]): Promise<any>; /** * 在所有 worker 中的执行命令 * * @remarks * 当 worker 中成功执行,且 this 上没有对应的成员时,则会自动新增对应的成员方法 * * @param exec - 命令信息 * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker,而发当前环境将不再保有所有权。 * @returns */ allExecCMD(exec: Exec, transfer?: Transferable[]): Promise<any[]>; /** * 设置命令 * @remarks * 会在Worker中添加一条命令,并且也会在实例自身上添加一个快捷命令(快捷方法 或 快捷属性) * * @param cmd * @param name - 命令的命名;默认会取 `cmd.name` 作为名字;当 cmd 是字符串时,name 是必须的 * @param isProperty - 添加到实例自身的快捷命令是否作为属性;如果是 true,则会在实例自身上生成快捷属性 * @returns */ setCMD(cmd: string | AnyFunction, name?: Optional<string>, isProperty?: Optional<boolean>): Promise<boolean[]>; /** * 移除命令 * @remarks * 会将 Worker 中的命令 和 自己实例上的对应快捷方法都给移除 * @param name * @returns */ removeCMD(name: string): Promise<boolean[]>; } /** * 命令执行信息 * @remarks * 命令有两种类型: * * + 函数: * * - 执行命令就是执行函数 * * - 执行命令的返回值就是函数的返回值 * * + 数据: * * - 执行命令就是访问这个数据对象 * * - 执行命令的返回值就这个数据本身 */ declare interface Exec { /** * 被执行对象的名字 */ name: string; /** * 函数式命令的参数 * @remarks * 如果传递了该选项,则命令一定会被当作函数来处理 */ args?: Optional<any[]>; /** * 函数式命令的 this 值 * @remarks * 如果传递了该选项,则命令一定会被当作函数来处理 */ this?: any; } /** * 命令执行的记录 */ declare interface ExecRecord extends Exec { /** * 本次执行的id */ id: string; } /** * 函数 或 函数代码 */ declare type Fun = AnyFunction | FunctionCode; /** * 定义函数的代码 * * @remarks * 可从 `fun.toString()` 得到 */ declare type FunctionCode = string; /** * 提取 函数 Fun 的返回类型 ExecRes<D> 中的 D 的类型 */ export declare type GetExecFunResultData<Fun extends (...args: any) => any> = GetExecResultData<Awaited<ReturnType<Fun>>>; /** * 提取 ExecRes<D> 中的 D 的类型 * @remarks * 用于提取 ExecResult 类型中的 D 的类型 */ export declare type GetExecResultData<ExecRes> = ExecRes extends { data: infer D; } ? D : ExecRes; /** * 获取 Worker 的回调函数 * @remarks * 这个函数就是用来根据回调的入参创建 worker 实例的 * * @param url - 用于创建 Worker 的 url; * @param name - Worker 的名字 */ export declare type GetWorker<W extends AbstractWorker = Worker> = (info: WorkerInfo) => W; /** * 默认的 getWorker * @param url * @param name * @returns */ export declare function getWorker_Default(info: WorkerInfo): Worker; /** * 定义命名的函数 * */ export declare interface INamedFunction { /** * 保存函数的变量名 */ name?: Optional<string>; /** * 函数 */ fun: AnyFunction; } /** * 命名函数的数组 */ export declare type INamedFunctionList = (AnyFunction | INamedFunction | INamedFunctionMap)[]; /** * 定义命名的函数 * * @remarks * 属性名字作为保存函数的变量名,即:函数名 */ export declare interface INamedFunctionMap { [name: string | number]: AnyFunction; } /** * 命名函数选项的综合定义 */ export declare type INamedFunctions = INamedFunctionList | INamedFunctionMap; /** * CallOptions 的类型保卫 * @param target * @returns */ export declare function isCallOptions(target: any): target is CallOptions; /** * worker 的代码选项 */ export declare interface IWorkerCodes { /** * 代码块 * @remarks * - `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 `Worker` 中的 `globalThis` 上,其中 名字会作为 属性名字; * * - `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 `Worker` 启动时作为顶层代码被立即执行; */ code?: Optional<CodePartOptions>; /** * 命名的函数 * * @remarks * 这些函数会被保存在 `Worker` 中的对应名字的全局变量中。 * * - `code` 和 `named` 中的所有具有名字的 函数和数据都会被挂载在 `Worker` 中的 `globalThis` 上,其中 名字会作为 属性名字; * * - `code` 和 `named`中的 匿名函数 以及 `iife` 中的函数 会被作为 立即调用函数在 `Worker` 启动时作为顶层代码被立即执行; */ named?: Optional<INamedFunctions>; /** * 在 Wokrer 中会被立即执行的函数 * @remarks * 这些函数会被作为 立即调用函数在 Worker 启动时作为顶层代码被立即执行; */ iife?: Optional<AnyFunction[]>; /** * 会作为 message 事件监听器的函数。 * @remarks * 这些函数会在 Worker 中接收 `message` 事件; * * **注意:** 并不是所有的 监听器 都会被直接添加到 `message` 事件上;只有以 函数名字(即:`JSIdentifier` 类型的监听器) 指定的 事件会被直接添加到 `message` 事件上,其它类型的监听器都是以函数调用并传递 `message` 事件参数的形式来响应 `message` 事件, */ message?: Optional<(AnyFunction | JSIdentifier | Partial<INamedFunction>)[]>; } /** * js 的标识符 * * @remarks * * 比如变量名 */ declare type JSIdentifier = string; export { listenMessages_Dep } /** * 将所有成员都 转为 异步h命令 * * @remarks * 所有的方法的入参不变,返回参数都变为解决值为对应类型的 Promise * 所有的属性都变为返回解决值为对应类型的 Promise 的方法 */ export declare type MembersToAsyncCMD<Target> = { [N in keyof Target]: AsyncCMD<Target[N]>; }; export declare type SortComparer<Item> = (a: Item, b: Item) => number; /** * 排序队列 * @remarks * 优先队列的极简实现;即优化了排序的性能,又保持代码精简; */ export declare class SortQueue<Item = any> { comparer: SortComparer<Item>; constructor(comparer: SortComparer<Item>, items?: Item[]); /** * 队列 * @remarks * 保存所有的元素 */ get queue(): Item[]; set queue(value: Item[]); protected _queue: Item[]; /** * 第一个元素 */ get first(): Item; /** * 最后一个元素 */ get last(): NonNullable<Item>; /** * 添加元素 * @param items * @returns 返回item最终的索引 */ add(item: Item): number; /** * 添加元素 * @param items */ addItems(items: Iterable<Item>): void; /** * 删除元素 * @param items * @returns 返回item删除前所在的索引 */ delete(item: Item): number; /** * 删除元素 * @param items */ deleteItems(items: Iterable<Item>): void; /** * 对队列中的所有元素重新排序 */ sort(): void; /** * 排序 item * @param item * @returns 如果item 不在队列中,返回 false;否则返回 true */ sortItem(item: Item): number; /** * 前向排序 * @param item * @returns 返回item最终的索引 */ forwardSort(item: Item): number; /** * 后向排序 * @param item * @returns 返回item最终的索引 */ backwardSort(item: Item): number; /** * 排序 item * @param index * @returns 返回item最终的索引 */ sortItemForIndex(index: number): number; /** * 前向排序 * @param index * @returns 返回item最终的索引 */ forwardSortForIndex(index: number): number; /** * 后向排序 * @param index * @returns 返回item最终的索引 */ backwardSortForIndex(index: number): number; } /** * 将所有方法都 转为 异步方法 * * @remarks * 所有的方法的入参不变,返回参数都变为解决值为对应类型的 Promise * * @typeParam Methods - 包含方法的对象 */ export declare type ToAsyncMethods<Methods extends INamedFunctionMap> = { [N in keyof Methods]: AsyncFun<Methods[N]>; }; /** * 动态Worker 抽像基类 * * @remarks * 动态 Worker 具备以下特点: * * - 往 Worker 中添加函数、全局变量 等 * * - 调用 Worker 中的任意全局函数 或 全局变量 * * - 像调用本地方法一样调用 Worker 里的方法 * * - 会自动给实例自身添加快捷命令 * * - 支持异步、流 * * - 支持异步和流互相嵌套 * * - 支持 Worker 和 SharedWorker */ export declare abstract class WorkerClient<W extends AbstractWorker = Worker> { constructor(named?: Optional<INamedFunctions>); /** * 实例的计数 * * @remarks * 用于给每次调用生成 id */ protected static instanceCount: number; readonly id: number; /** * Worker 的实例 */ abstract worker: DWorker<W>; /** * 消息端口 */ get port(): MessagePort; /** * 获取 Worker 和 对应的 消息端口 */ get workerAndPort(): [DWorker<W>, MessagePort]; /** * 获取消息端口 * @param worker * @returns */ getPort(worker: W): MessagePort; /** * 正在执行中的任务数 */ abstract executingCount: number; /** * 执行已开始 * @remarks * 开始执行 */ execStarted(worker: DWorker<W>, execRec: ExecRecord): void; /** * 执行已开始 * @remarks * 开始执行 */ execEnded(worker: DWorker<W>): void; /** * 执行命令的计数 * * @remarks * 用于给每次执行命令时生成 id */ protected execCount: number; /** * 获取本次执行的执行 id * @param cmdName * @returns */ getExecId(cmdName?: Optional<string>): string; /** * 根据调用信息生成调用记录数据 * @param exec - 调用信息 * @returns */ getExecRecord(exec: Exec): ExecRecord; /** * 监听响应 * @param id * @returns */ listenResponse(id: string, worker: DWorker<W>): Promise<any>; /** * 执行 worker 中的命令 * * @remarks * 当 worker 中成功执行,且 this 上没有对应的成员时,则会自动新增对应的成员方法 * * @param exec - 命令信息 * @param transfer - 传递给 Worker 的可传递对象。这些对象的所有权将被转移给 Worker,而发当前环境将不再保有所有权。 * @returns */ execCMD(exec: Exec, transfer?: Transferable[]): Promise<any>; /** * 往自身上添加命令成员 * @remarks * 会给实例自身上添加一个执行命令的快捷命令 * * @param name * @param isProperty - 添加到实例自身的快捷命令是否作为属性;如果是 true,则会在实例自身上生成快捷属性 */ setCMDToSelf(name: string, isProperty?: Optional<boolean>): boolean; } /** * worker 的信息 */ export declare interface WorkerInfo { /** * worker 要加载的代码的url */ url: string; /** * worker 的名字 */ name: string; /** * worker 客户端 的 id */ clientId: number; /** * worker 的 id */ id: number; } /** * worker 优先级比较器 * @remarks * 按照 executingCount 的从小到大排列 * @param a * @param b */ export declare function workerPriorityComparator<W extends AbstractWorker>(a: DWorker<W>, b: DWorker<W>): number; export { }