I'm trying to offload some intensive data processing to a WebWorker in a react app. If I call any asynchronous function within the onmessage handler, using promises or async/await, I get:
ReferenceError: _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default is not defined
Here's my worker:
const DataSyncWorker = () => {
self.doSyncing = async () => {
return null;
};
self.onmessage = e => {
if (!e) return;
console.log(`worker received message in listener callback: ${e.data}`);
self.doSyncing();
self.postMessage(`SYNC_COMPLETE`);
};
};
export default DataSyncWorker;
And the setup file for creating the Worker:
export default class WebWorker {
constructor(worker) {
const code = worker.toString();
const blob = new Blob([`(${code})()`]);
return new Worker(URL.createObjectURL(blob));
}
}
And invoking it:
import DataSyncWorker from './workers/DataSyncWorker';
import WebWorker from './workers/workerSetup';
const App = () => {
const dataSyncWorker = new WebWorker(DataSyncWorker);
dataSyncWorker.postMessage(`START_SYNC`);
dataSyncWorker.addEventListener(`message`, event => {
console.log(`index: message from worker: ${e.data}`);
});
}
If I change doSyncing to not be async, everything works fine. This is a simplified example, which I've confirmed still exhibits the same behavior. But I'm not able to use axios, or any other async function. It's my understanding that this should be possible, and, given the error, I am wondering if my issue is related to babel/webpack. Or perhaps I'm doing something else wrong. Any help is greatly appreciated. Thanks.
I solved this with a few changes:
First, I incorporated worker-loader library, using the inline type import, like:
import DataSyncWorker from 'worker-loader!./workers/DataSyncWorker';
And then, I had to unwrap the inner functions from the containing method of the original implementation, so DataSyncWorker now looks like this:
doSyncing = async () => {
return null;
};
self.onmessage = e => {
if (!e) return;
console.log(`worker received message in listener callback: ${e.data}`);
doSyncing();
self.postMessage(`SYNC_COMPLETE`);
};
The other code remains unchanged, and now everything works.
I believe you could use an alternate approach, involving modifying the webpack.config.js, with these additions to the modules.rules section:
{
test: /\.worker\.js$/,
use: ['worker-loader', 'babel-loader'],
include: [path.join(__dirname, 'src/workers')]
},
and then updating the name of your worker file so it's matched by the test condition, and updating it's import, etc, but I haven't tried that yet, and the inline method seemed simpler.