Web Worker 线程池方案 - threads.js 实现示例

888 阅读1分钟

Worker 通信 API 很简单,只有 postMessage 和 onmesssage 两个,Worker 通信 API 虽然简洁,但缺少易用性,增加了调试的困难,降低了排查问题的效率。

此前经过调研分析(调研报告),我司 Web Worker 方案基于 Comlink实现,但随着业务增长,单 worker 实例难以满足需求,因此着手探索 Web Worker 线程池方案实现,最终综合易用性,插件齐全,库包大小和兼容性等方面考虑,选择接入 threads.js

官方示例过于简单,以下是我司接入示例,以作参考:

  1. webpack 引入插件
    const ThreadsPlugin = require('threads-plugin');
    
    ....
    new ThreadsPlugin({ globalObject: 'self' }),
    ....
    
  2. jsconfig.json / tsconfig.json / babel.config.js 响应配置(参考官方文档)
  3. 主文件 pool.ts
    import { spawn, Pool, Worker } from 'threads';
    // @ts-ignore
    import mainWorkerUrl from 'threads-plugin/dist/loader?name=main-worker!./worker/main.worker.ts';
    const pool = Pool(() => spawn(new Worker(mainWorkerUrl)), 4);
    
    import type { PageList, RangeTime } from '#/player';
    import type { LogList } from '#/dev-tool';
    
    
    const getFormatLogSource = async (pages: PageList, logList: LogList, rangeTime: RangeTime) => {
     return pool.queue(worker => worker.formatLogSource(pages, logList, rangeTime))
    }
    
    const logSearch = async (logList: LogList, payload: { type: string, searchKey: string }) => {
     return pool.queue(worker => worker.logSearch(logList, payload))
    }
    
    export {
     getFormatLogSource,
     logSearch,
    }
    
    这里需要注意的是 Webpack5 引入 worker 文件存在一定 bug,必须使用如下语句:
    import mainWorkerUrl from 'threads-plugin/dist/loader?name=main-worker!./worker/main.worker.ts';
    
  4. worker 文件,main.worker.js
    import { expose } from 'threads/worker';
    
    import { formatLogSource, logSearch } from './modules/log';
    
    
    expose({
      formatLogSource,
      logSearch,
    });
    
  5. 具体业务文件,modules/log.ts
    const logSearch = () => {};
    const formatLogSource = () => {};
    export {
      formatLogSource,
      logSearch,
    }
    
  6. 其他业务,modules/xxxx.ts
  7. 应用
    import { logSearch } from '@/worker-api/pool';
    
    const runTask = async () => {
        const logList = await logSearch();
    }
    
    import { xxx } from '@/worker-api/pool';
    
    xxx().then(res => console.log(res));
    

运行结果

image.png