0

My worker sends a message to the main script, and then the main script responds. I want to wait for the response before continuing the worker because the response contains the information I need (memoryAvailable).

Main.js

export function convert(){
let managingWorker = new Worker("managingWorker.js");
let fileNode = document.querySelector('.fileInput');
managingWorker.postMessage({fileList:fileNode.files, msgType:"processData", options:{delimiter: 
document.querySelector('#specifyDelimiter').value.trim() || ","}});

managingWorker.onmessage = function(e){
    switch(e.data.msgType){
        case "memoryInfoRequested":
            let memAvail = performance.memory.jsHeapSizeLimit - performance.memory.totalJSHeapSize;
            managingWorker.postMessage({msgType:"memoryInfoReceived", memoryAvailable: memAvail});
            break;
     //Other cases for updating the UI
   }

managingWorker.js
 
 let memoryAvailable = 0;

 onmessage = function(e){
    switch(e.data.msgType){
    case "processData":
            workerStuff(e)
    break;
    case "memoryInfoReceived":
        memoryAvailable = e.data.memoryAvailable
    break;
    }
 }

function workerStuff(f){
    //do stuff
    postMessage({msgType:"memoryInfoRequested"})
    //do more stuff if there is enough memory available, else wait

}

I've already tried: Putting a while loop in the worker while(memoryAvailable < 5){//do nothing} but then the worker gets stuck in the while loop and never has a chance to receive the message.

I'm currently thinking I could maybe use async await and setTimeout to pause for x milliseconds, then by the time the promise is resolved, the message should be delivered, but even if I get this to work, it's not the optimal solution. *My brain is a bit fried now, so maybe after dinner I'll try something like this.

ThomasRones
  • 657
  • 8
  • 29
  • 1
    Here is a [generic solution](https://stackoverflow.com/questions/5408406/web-workers-without-a-separate-javascript-file/48470558#48470558) for awaiting a worker task as a promise. – trincot Dec 09 '20 at 17:16
  • 1
    @ThomasRones I've modified my answer to include a loop that waits for there to be enough memory available. – TKoL Dec 10 '20 at 09:54

1 Answers1

1

So, I haven't tested this but this is how I think I would handle it:

managingWorker.js
 

 let waitForMemoryResolve = () => {};

 onmessage = function(e){
    switch(e.data.msgType){
    case "processData":
            workerStuff(e)
    break;
    case "memoryInfoReceived":
        memoryAvailable = e.data.memoryAvailable;
        waitForMemoryResolve(memoryAvailable);
    break;
    }
 }

function workerStuff(f){
    //do stuff
    let memoryAvailable = await waitForMemory();
    while (memoryAvailable < 2000) { // or whatever memory you want
         await new Promise(r => setTimeout(r, 500)); // wait a half second and check again
         memoryAvailable = await waitForMemory();
    }
    
   // once here, we have > 2000 memory, so begin work

}

async function waitForMemory() {
    return new Promise((resolve, reject) => {
      waitForMemoryResolve = resolve;
      postMessage({msgType:"memoryInfoRequested"})
    })   
}

You can pass your 'resolve' function from inside a promise elsewhere, and allow other parts of the code to resolve your promise. I'd use it like that.

Again, haven't tested this, but I think the idea is sound

TKoL
  • 13,158
  • 3
  • 39
  • 73
  • 1
    You wouldn't use a global `memoryAvailable` variable at all then, but in general this is the way to go – Bergi Dec 09 '20 at 22:18
  • 1
    @Bergi ah, true, I wasn't really thinking about changing his code so much as adding a feature to get a result back with a promise, but you're right, that global variable is not relevant in this format – TKoL Dec 10 '20 at 09:08