Web workers example with queue

by PhilQ

HTML

<script id="worker1" type="javascript/worker">
  self.onmessage = function(e) {
  	self.postMessage({
    	status: 'running',
      message: 'Running task ' + e.data.id + '...'
    });

		setTimeout(function(){
      self.postMessage({
        status: 'done',
        message: 'Finished task ' + e.data.id
      });
    }, 1000 + Math.random()*2000);
	};
</script>

JavaScript

// Create worker code (instead of external file)
var blob = new Blob([
  document.querySelector('#worker1').textContent
], {
  type: "text/javascript"
});
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var workerObjectUrl = window.URL.createObjectURL(blob);


// Web worker set-up
var numberOfCores = 4; // See: https://github.com/oftn-oswg/core-estimator
var workers = new Array(numberOfCores).fill(null);
var tasks = [];
var tasksRemaining = 0;
var tasksCompletedCallback = () => {};

// Define web worker handling
function handleWorker(worker, e, workerIdx) {
    let txtColor = (e.data.status === 'running') ? 'color:orange;': 'color:green;';
    console.log('W' + workerIdx + ': %c' + e.data.message, txtColor);
    if (e.data.status === 'done') {
    	tasksRemaining--;
    	if (tasks.length > 0) {
    		worker.postMessage(tasks.shift());
      } else if (tasksRemaining === 0) {
      	tasksCompletedCallback();
      }
    }
}

// Initiate web workers
workers.map((v, i, a) => {
	workers[i] = new Worker(workerObjectUrl);
  workers[i].onmessage = function(e) {
  	handleWorker(this, e, i);
  }
});

// Function to control, queue and starting tasks
function runTasks(_tasks, _callback) {
	if (tasksRemaining > 0 || tasks.length > 0) {
  	console.error('Previous tasks did not finish yet');
    return;
  }
  tasks = _tasks;
  tasksRemaining = tasks.length;
  tasksCompletedCallback = _callback;
	let max = Math.min(tasks.length, workers.length);
  for (let i = 0; i < max; i++) {
  	workers[i].postMessage(tasks.shift());
  }
}


// Start running tasks
runTasks(
	[
    {id:1},
    {id:2},
    {id:3},
    {id:4},
    {id:5},
    {id:6},
    {id:7},
    {id:8},
    {id:9},
    {id:10}
  ], () => {
  	console.log('--- DONE ---');
    
    // Run next set of tasks
    runTasks(
      [
        {id:'A'},
        {id:'B'},
        {id:'C'},
        {id:'D'},
        {id:'E'},
        {id:'F'}
      ], () => {
        console.log('--- DONE ---');
      }
    );
  }
);