JavaScript WebWorkerでCRC32計算 スレッドによる非同期計算処理の例

以前と投稿したCRC32計算をWebWorker(スレッド)で非同期にしたものです。計算中でもUI関連の処理が停止しないため、快適な操作を維持できます。

WebWorker

async-awaitの並列処理ではなく、マルチスレッド処理を行うAPIです。
詳しくは検索で

いきなりソースコード

export async function main(){
    
    let crcWorker = await CRC32Worker.open();   
    let data = new ArrayBuffer(100*1024*1024);
    //data : crcを計算するデータ、ファイルとか

    // 待っている間、UIを止めない
    // workerに送ったdataは無効(空)に
    let ret = await crcWorker.crc32(data);
   
    data = ret.data;// 使い終わったデータを受け取る 
    let crs32 = ret.crc32;

    console.log(crs32.toString(16));
}

interface CRC32WorkerResult{
    crc32 : number,
    data : ArrayBuffer, // データ返還
}

class CRC32Worker{
    private worker : Worker;
    private constructor(worker : Worker){
        this.worker = worker;
    }

    static async open(){
        // JSファイル
        //return new CRC32Worker(new Worker("crc-worker.js"));  

        // 埋め込みJSソースコード
        let codeURL = URL.createObjectURL(new Blob([workerCode]));
        return new CRC32Worker(new Worker(codeURL));  
    }

    // copy=false なら dataは無効(空)に 
    async crc32(data : ArrayBuffer, copy : boolean = false){
       return await new Promise<CRC32WorkerResult>( (rs,rj)=>{
            this.worker.postMessage(data, copy? [] : [data]);
            this.worker.onmessage = (ev)=>{
                rs(ev.data);
            }
            this.worker.onerror = rj;
        });
        
    }
}

// 埋め込みJSソースコード
let workerCode = `
onmessage = (e) => {
    let crc32 = new CRC32().crc32(new Uint8Array(e.data));
    //transferを使わない場合、送信時に複製、遅くなる可能性
    postMessage({ crc32, data: e.data }, [e.data]); //データ返還
    //postMessage(crc);//データ返還なし
};
//---------------------------------------
// crc32
class CRC32 {
    static table = [];
    constructor() {
        if (CRC32.table.length > 0) {
            return;
        }
        CRC32.initTable();
    }
    static initTable() {
        for (let i = 0; i < 256; ++i) {
            let r = i;
            for (let j = 0; j < 8; ++j) {
                if ((r & 1) == 1) {
                    r = 0xedb88320 ^ (r >>> 1);
                }
                else {
                    r = r >>> 1;
                }
            }
            CRC32.table[i] = r >>> 0;
        }
    }
    crc32(data) {
        let crc = 0xffffffff;
        let tbl = CRC32.table;
        for (let o of data) {
            crc = (crc >>> 8) ^ tbl[(crc ^ o) & 0xff];
        }
        crc = crc ^ 0xffffffff;
        return crc >>> 0;
    }
}
CRC32.initTable();
`;

埋め込みソースコードのTSファイル

interface CRC32WorkerResult{
    crc32 : number,
    data : ArrayBuffer, // データ返還
}

// window.postMessageと誤認されエラーにならないように
declare function postMessage(ev : any, transfer : any) : any;

onmessage = (e) => {
    
    let crc32 = new CRC32().crc32(new Uint8Array(e.data));
    
    //transferを使わない場合、送信時に複製、遅くなる可能性
    postMessage({crc32, data:e.data}, [e.data]);//データ返還
    //postMessage(crc);//データ返還なし
};
//---------------------------------------
// crc32
class CRC32{
    static table : number[] = [];
    constructor(){
        if(CRC32.table.length > 0){ return; }
        CRC32.initTable();
    }
    static initTable(){
        for(let i=0; i<256; ++i){
            let r = i;
            for(let j=0; j<8; ++j){
                if( (r & 1) == 1 ) { r = 0xedb88320^(r>>>1); }
                else { r = r >>> 1; }
            }
            CRC32.table[i] = r >>> 0;
        }
    }

    crc32(data : Uint8Array){
        let crc = 0xffffffff;
        let tbl = CRC32.table; 
        for(let o of data){
            crc = (crc >>> 8) ^ tbl[(crc ^ o)&0xff];
        }
        crc = crc^0xffffffff;  
        return crc >>> 0;
    }
}
CRC32.initTable();

この記事が役に立ったという方は、サポートお願いします。今後の製作の励みになります。