I'm using a webworker to calculate coordinates and values belonging to those places. The calculations happen in the background perfectly, keeping the DOM responsive. However, when I send the data from the webworker back to the main thread the DOM becomes unresponsive for a part of the transfer time.
My webworker (sending part):
//calculates happen before; this is the final step to give the calculated data back to the mainthread.
var processProgressGEO = {'cmd':'geoReport', 'name': 'starting transfer to main', 'current': c, 'total': polys}
postMessage(processProgressGEO);
postMessage({
'cmd':'heatmapCompleted',
'heatdata': rehashedMap,
'heatdatacount': p,
'current': c,
'total': polys,
'heatmapPeak': peakHM,
});
self.close();
The variable rehashedMap
in the code snippet above is an object with numerical keys. Each key contains an array
with another object
in.
My mainthread (only the relevant part:)
var heatMaxforAuto = 1000000; //maximum amount of datapoints allowed in the texdata. This takes into account the spread of a singel datapoint.
async function fetchHeatData(){
return new Promise((resolve, reject) => {
var numbercruncher = new Worker('calculator.js');
console.log("Performing Second XHR request:");
var url2 = 'backend.php?datarequest=geodata'
$.ajax({
type: "GET",
url: url2,
}).then(async function(RAWGEOdata) {
data.georaw = RAWGEOdata;
numbercruncher.onmessage = async function(e){
var w = (e.data.current/e.data.total)*100+'%';
if (e.data.cmd === 'geoReport'){
console.log("HEAT: ", e.data.name, end(),'Sec.' );
}else if (e.data.cmd === 'heatmapCompleted') {
console.log("received Full heatmap data: "+end());
data.heatmap = e.data.heatdata;
console.log("heatData transfered", end());
data.heatmapMaxValue = e.data.heatmapPeak;
data.pointsInHeatmap = e.data.heatdatacount;
console.log("killing worker");
numbercruncher.terminate();
resolve(1);
}else{
throw "Unexpected command received by worker: "+ e.data.cmd;
}
}
console.log('send to worker')
numbercruncher.postMessage({'mode':'geo', 'data':data});
}).catch(function(error) {
reject(0);
throw error;
})
});
}
async function makemap(){
let heatDone = false;
if (data.texdatapoints<= heatMaxforAuto){
heatDone = await fetchHeatData();
}else{
var manualHeatMapFetcher = document.createElement("BUTTON");
var manualHeatMapFetcherText = document.createTextNode('Fetch records');
manualHeatMapFetcher.appendChild(manualHeatMapFetcherText);
manualHeatMapFetcher.id='manualHeatTriggerButton';
manualHeatMapFetcher.addEventListener("click", async function(){
$(this).toggleClass('hidden');
heatDone = await fetchHeatData();
console.log(heatDone, 'allIsDone', end());
});
document.getElementById("toggleIDheatmap").appendChild(manualHeatMapFetcher);
}
}
makemap();
The call to the end()
function is needed to calculate the seconds since the start of the webworker. It returns the difference between a global set starttime and the time of calling.
What shows in my console:
HEAT: starting transfer to main 35 Sec. animator.js:44:19
received Full heatmap data: 51 animator.js:47:19
heatData transfered 51 animator.js:49:19
killing worker animator.js:52:19
1 allIsDone 51
The issue: My DOM freezes between the start of the data transfer and the message after receiving the full heatmap data. This is the phase between the first and second message in my console. It takes 16 seconds to transfer, but the DOM only goes unresponsive once for a part of that time. Webworkers can't share data with the mainthread, so a transfer is needed.
Question:
Firstly, how to prevent the freeze of the the DOM during the onmessage
phase of the webworker? Secondly, more out of curiosity: how can this freeze only occur during a part of that phase, as these are triggered by two consecutive steps with nothing going on in between?
What I tried so far:
- Doing a for-loop over the rehashedMap and return key by key. This still triggers DOM freezes; shorter, but more than once. In rare occurrences it takes the tab down.
- Looking for a way to buffer the
onmessage
phase; however, there's no such option specified in the documentation (https://developer.mozilla.org/en-US/docs/Web/API/Worker/onmessage) as compared to thepostMessage
phase (https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage). Am I missing something here? - As a test I replaced the rehashedMap with an empty object; this didn't cause any freezes in the DOM. Of course, this is leaves me without access to the calculate data.
- I looked at this thread on SO:Javascript WebWorker - Async/Await But I'm not sure how to compare that context to mine.