You absolutely can use async-await with WebWorkers and in WebWorkers.
And if some prehistoric browser doesn't support the async-await keywords,
you can transpile them down to ES5 with promises.
This even worked for IE11.
Here's the tsconfig to transpile promises to ES5:
{ "compileOnSave": true, "compilerOptions": { "target": "ES5", //"target": "es5", //"module": "amd", // define, export, like playground // "module": "commonjs", // require "module": "ES2015", // just like typescript // "module": "system", // System.register // "module": "umd", // factory, require, exports // "module": "esnext", // like typescript // "module": "none", // Object.defineProperty, require // "module": "commonjs", "lib": [ "DOM", "ES2016", "ES2015.Promise", "ES2015.Proxy" ], "noImplicitAny": true, "noEmitOnError": true, "removeComments": true, "sourceMap": false, "outDir": "../../wwwroot/pdfstamps", "rootDir": "./", "allowUnreachableCode": true //,"alwaysStrict ": true, }, "exclude": [ "node_modules", "wwwroot" ], "include": [ "**/*" ] }
Here's a sample, on how to do it.
It calls a worker function with await, and expects the result. In processData, the worker creates random delays between 1 and 5 seconds, and then returns the data you passed. 50% of the time ( as in getRandomInt(1,2) ), it will return an exception, so you see this handles exceptions as well.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="Pragma" content="no-cache"> <title>Whitespace Removal Benchmark</title> <style> .loader { width: 30px; aspect-ratio: 4; --_g: no-repeat radial-gradient(circle closest-side,#000 90%,#0000); background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; background-size: calc(100%/3) 100%; animation: l7 1s infinite linear; } @keyframes l7 { 33% { background-size: calc(100%/3) 0%,calc(100%/3) 100%,calc(100%/3) 100% } 50% { background-size: calc(100%/3) 100%,calc(100%/3) 0%,calc(100%/3) 100% } 66% { background-size: calc(100%/3) 100%,calc(100%/3) 100%,calc(100%/3) 0% } } </style> </head> <body> <h1>Whitespace Removal Benchmark</h1> <div id="result"> <div class="loader" style="display: inline-block;"></div> <div style="display: inline-block; font-size: 5mm;" class="loading">Benchmark running </div> <div class="loader" style="display: inline-block;"></div> </div> <!-- https://css-loaders.com/dots/ --> <script> const workerCode = `"use strict"; function cryptoRand() { const randomBuffer = new Uint32Array(1); (crypto || msCrypto).getRandomValues(randomBuffer); return ( randomBuffer[0] / (0xffffffff + 1) ); } function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(cryptoRand() * (max - min + 1)) + min; } function sleep(interval) { return new Promise( function (resolve, reject) { let wait = setTimeout( function () { clearTimeout(wait); if(getRandomInt(1,2) % 2 == 0) resolve(); else reject(new Error("Promise timed out ! ")); } , interval ); }); } async function processData(data) { let interval = getRandomInt(1000, 5000); await sleep(interval); return data; } async function handleSomeTask(id, data) { try { // Process the data const result = await processData(data); // throw new Error("hello"); self.postMessage({ "id": id, "err":null, "result": result }); } catch (err) { self.postMessage({ "id": id, "err":err, "result": null }); } } self.onmessage = function(event) { const { id, data } = event.data; handleSomeTask(id, data); }; `; const blob = new Blob([workerCode], { type: 'text/javascript' }); const worker = new Worker(URL.createObjectURL(blob)); worker.onmessage = function(event) { const { id, err, result } = event.data; // console.log("received", event.data); if (err != null) { const reject = worker.workerErrorCallbacks.get(id); if (reject) { reject(err); worker.workerSuccessCallbacks.delete(id); worker.workerErrorCallbacks.delete(id); } } else { const resolve = worker.workerSuccessCallbacks.get(id); if (resolve) { resolve(result); worker.workerSuccessCallbacks.delete(id); worker.workerErrorCallbacks.delete(id); } } }; function generateRandom32BitInteger() { var array = new Int8Array(4); (window.crypto || window.msCrypto).getRandomValues(array); var dataView = new DataView(array.buffer); var uint = dataView.getUint32(); // var f = uint / (0xffffffff + 1); // 0xFFFFFFFF = uint32.MaxValue (+1 because Math.random is inclusive of 0, but not 1) // return f; return uint; } function generateRandom128BitInteger() { const array = new Uint8Array(16); crypto.getRandomValues(array); let value = 0n; for (let i = 0; i < array.length; i++) { value = (value << 8n) + BigInt(array[i]); } return value; } function generateRandomUuid() { const array = new Uint8Array(16); crypto.getRandomValues(array); let value = 0n; for (let i = 0; i < array.length; i++) { value = (value << 8n) + BigInt(array[i]); } // return value; const hexString = value.toString(16).padStart(32, '0'); // Format the hex string into UUID format const uuid = `${hexString.slice(0, 8)}-${hexString.slice(8, 12)}-${hexString.slice(12, 16)}-${hexString.slice(16, 20)}-${hexString.slice(20)}`; return uuid; } async function callWorkerFunction(worker, data) { if (!worker.workerSuccessCallbacks) { worker.workerSuccessCallbacks = new Map(); worker.workerErrorCallbacks = new Map(); // worker.callbackId = 0;; } // const id = Math.random(); // Generate a unique identifier // const id = generateRandomUuid(); // const id = generateRandom128BitInteger(); const id = generateRandom32BitInteger(); // const id = worker.callbackId++; return new Promise( function (resolve, reject) { // worker.onmessage = function(event) // { // console.log("received event", event.data); // if (event.data.id === id) // { // resolve(event.data.result); // // worker.terminate(); // Optional: Terminate the worker after the result // } // }; worker.workerSuccessCallbacks.set(id, resolve); worker.workerErrorCallbacks.set(id, reject); worker.postMessage({ id, data }); } ); } function generateRandomString(min, max) { const length = Math.floor(Math.random() * (max - min + 1)) + min; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charactersLength = characters.length; let result = []; for (let i = 0; i < length; i++) { result.push(characters.charAt(Math.floor(Math.random() * charactersLength))); } return result.join(""); } async function testCall() { try { const randomString = generateRandomString(5, 15); let passedData = { "hello": "kitty", "foo": "bar", "something": randomString }; const result = await callWorkerFunction(worker, passedData); console.log("result for " + randomString + ":", result); } catch (err) { console.log("failed:", err); } } function test() { for (let i = 0; i < 20; ++i) { testCall(); } } test(); </script> </body> </html>
__awaiteris defined then__awaiter?