Shoving slow stuff into a Web Worker

Once you decide to end your IE support where Microsoft does (11), a whole world of opportunities opens up. One of those opportunities is Web Workers, and it is going to save my bacon.

Web Workers provide a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface.

MDN

As we got more years of data for our metrics in the Quality of Life project, I’d occasionally hit a really long lag when switching between metrics. Some dev tools spelunking later and I discovered the problem.

I do a Jenks breaks calculation with the data values of a metric across all years of data. We have 12 years for some metrics now. 12 * 464 values = your Jenks calculation is going to take a long time; 1.3 seconds on my smoking fast rig, a helluva lot longer on a phone. That’s way too long to lock up a UI.

So…a Web Worker is born.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import isNumeric from '../modules/isnumeric';
import jenks from '../modules/jenks';
// Tom MacWright's Jenks function. Has anybody knighted this guy yet?


self.addEventListener('message', function(e) {
let data = e.data;
self.postMessage(mapBreaks(data[0], data[1], data[2]));
self.close();
}, false);


function mapBreaks(data, years, breaks = 5) {
let jenksArray = [];
for (let i in data) {
for (let y = 0; y < years.length; y++) {
if (isNumeric(data[i][`y_${years[y]}`])) {
jenksArray.push(data[i][`y_${years[y]}`]);
}
}
}
return jenks(jenksArray, breaks);
}

Then call it in the main thread.

1
2
3
4
5
let worker = new Worker('./js/workers/jenksbreaks.js');
worker.addEventListener('message', function(e) {
// breaks array is e.data
}, false);
worker.postMessage([this.sharedState.data.map, this.sharedState.years, 5]);

Now the rest of the app can keep trucking while Jenks breaks are being calculated. It’ll be in v3 of the Quality of Life project, which will (maybe) be ready for testing at the end of October.