I am trying to send a message from one worker to the other (and then respond back through a SharedArrayBuffer). But I can't find any information on posting a message to another worker from within a worker. How would I go about doing it? (I tried posting the worker itself as a message, but it doesn't work).
Here is my code:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script type='text/javascript'>
var s_curFile;
var s_curFile2;
var s_SAB = new SharedArrayBuffer(65563);
var u8buf = new Uint8Array(s_SAB);
function JSprocessFilePicker( input )
{
let url = input.value;
let ext = url.substring( url.lastIndexOf( '.' ) + 1 ).toLowerCase();
if ( input.files && input.files[0] && ( ext == "txt" ) )
{
s_curFile = input.files[0];
try {
fileWorker.postMessage({
'cmd' : 'file',
'file' : s_curFile
});
} catch(e) {
alert('Can\'t spawn files to worker - '+e)
}
try {
worker.postMessage({
'cmd' : 'run'
});
} catch(e) {
alert('Can\'t spawn files to worker - '+e)
}
}
}
u8buf[0] = 0;
var worker = new Worker('worker.js');
var fileWorker = new Worker('fileWorker.js');
try {
worker.postMessage({
'cmd' : 'SAB',
'sab' : s_SAB
}, fileWorker);
} catch(e) {
alert('Can\'t send Shared Array Buffer to worker - '+e);
}
try {
fileWorker.postMessage({
'cmd' : 'SAB',
'sab' : s_SAB
});
} catch(e) {
alert('Can\'t send Shared Array Buffer to worker - '+e);
}
var input = document.createElement( "input" );
input.setAttribute( "id", "file_picker" );
input.setAttribute( "type", "file" );
input.setAttribute( "accept", ".fzp" );
input.setAttribute( "onchange", "JSprocessFilePicker(this)" );
</script>
<button onclick="input.click();">Open</button>
</body>
</html>
worker.js:
var s_SAB;
var u8buf;
var fileWorker;
self.onmessage = function(e) {
if( e.data.cmd === 'SAB' )
{
s_SAB = e.data.sab;
u8buf = new Uint8Array(s_SAB);
fileWorker = e.data.fileWorker;
console.log(s_SAB);
console.log(fileWorker);
}
else if( e.data.cmd === 'run' )
{
try {
fileWorker.postMessage({
'cmd' : 'load'
});
} catch(e) {
console.log('Can\'t post message from web worker - '+e); //I GET AN ERROR HERE
}
while(u8buf[0] === 0)
{
//This loop here I am doing heavy processing, that i cannot change really
console.log("worker waiting for file...\n");
}
console.log("worker got data!\n");
let Idx;
for (Idx = 0; Idx < 20; ++Idx) {
console.log(u8buf[Idx+1]);
}
}
fileWorker.js
var s_curFile;
var s_SAB;
var u8buf;
let xhrReq = new XMLHttpRequest();
xhrReq.overrideMimeType('text/plain; charset=x-user-defined');
self.onmessage = function(e) {
if( e.data.cmd === 'file' )
{
s_curFile = e.data.file;
console.log("got file!");
}
else if( e.data.cmd === 'SAB' )
{
s_SAB = e.data.sab;
u8buf = new Uint8Array(s_SAB);
console.log(s_SAB);
}
else if( e.data.cmd === 'load' )
{
let uri = URL.createObjectURL(s_curFile.slice(40, 100));
xhrReq.open('GET', uri, true);
xhrReq.send(null);
URL.revokeObjectURL(uri);
let Idx;
let sz = xhrReq.response.length;
console.log("Response Size: "+sz);
for (Idx = 0; Idx < sz; ++Idx) {
u8buf[Idx+1] = xhrReq.response.charCodeAt(Idx);
}
u8buf[0] = 1;
}
}
TL;DR Do you really want to do this?
In order to even have access to a
SharedArrayBuffer
you have to set some specific headers to meet the post-Spectre security requirements. You can useAtomics.wait
* to block a worker thread on change to a shared buffer to communicate from one worker to another if you really want...Alternatively:
You could simply forward messages from one worker to the main thread using a simple
postMessage
to other workers, a very basic pub-sub if you will. Much easier to pull off.* Only works with an
Int32Array
as the underlying buffer, notUint8Array
like you have in your example.