2

I'm trying to speed up a javascript website I'm building with a web worker. This is totally new for me, I'm learning.

I managed to have this web worker run and do what it should (i.e. load some CSV data, transform it and send it back).

But It seems to me that this web worker is starting his job a little bit too late (about 500 ms after I send him the postMessage)

Is this normal ?
How come that the worker doesn't start sooner ?
What can I do ?

Here is the worker:

self.postMessage('A. !!! Worker on');
self.onmessage = function(event) {
    var n=event.data;
    self.postMessage('['+n+'] B. Worker started');
    // (...)
}

Here is the handling of the worker:

window.timer = Date.now();
window.timerTotal = window.timer;

function loadData(n){
    console.log('A. !!! Begin loadData function (dt=' + (Date.now()-window.timer) + ') (T='+(Date.now()-window.timerTotal)+')'); window.timer = Date.now();

    var worker = new Worker('my_task.js');
    worker.onmessage = function(event) {
        if ( (typeof event.data)==='string'){
            console.log('Web Worker: ' + event.data + ' (dt=' + (Date.now()-window.timer) + ') (T='+(Date.now()-window.timerTotal)+')'); window.timer = Date.now();
        }
        else if ( (typeof event.data)==='object'){
            console.log('!!! Web Worker returned object: (dt=' + (Date.now()-window.timer) + ') (T='+(Date.now()-window.timerTotal)+')'); window.timer = Date.now();
            createGraphs2(event.data);
        }
    };

    if(n===100){
        d3.csv("data/Movies100-V2.0.csv", function(error, data_csv) {
            createGraphs(data_csv);
        });
    }
    else if(n==='10k'){
        worker.postMessage(n);
    console.log('postMessage send to web worker (dt=' + (Date.now()-window.timer) + ') (T='+(Date.now()-window.timerTotal)+')'); window.timer = Date.now();
    }
}

loadData('10k');

// (...) lots of functions like createGraphs2(data)

And here is the log:

Begin loadData function (dt=7) (T=7)
postMessage send to web worker (dt=1) (T=8)
Web Worker: A. !!! Worker on (dt=524) (T=591)
Web Worker: [10k] B. Worker started (dt=1) (T=593)

Thanks!

UPDATE:

When I send a postMessage to the worker at the same time as I launch a veryLongScript:

veryLongScript();
worker.postMessage(n);

Most of the time, the worker responds after the veryLongScript.

(veryLongScript)
Web Worker: A. !!! Worker on (dt=301) (T=12464)
Web Worker: [10k] B. Worker started (dt=1) (T=12465)
Web Worker: [10k] C. dependencies loaded (dt=600) (T=13065)

and sometimes the worker responds something before and after the veryLongScript, but it doesn't seem to work in parallel.

Web Worker: A. !!! Worker on (dt=1235) (T=1416)
Web Worker: [10k] B. Worker started (dt=0) (T=1418)
(veryLongScript)
Web Worker: [10k] C. dependencies loaded (dt=619) (T=13168)

stallingOne
  • 3,633
  • 3
  • 41
  • 63

1 Answers1

2

When you create a new worker by

new Worker('my_task.js');

It is only at this point that the browser makes a request to the server to get the my_task.js to run in the worker. You then are waiting for a request to your server to be made and returned, as well as the worker being started.

I have made a cut down example of your code at http://plnkr.co/edit/MlabLs4HafnIscBbnPJv?p=preview . For me it reports the time to start a worker as ~130ms for Chrome. However, the network inspector states that it takes ~90ms to fetch the script. Thus leaving 40ms for the actual startup time of the worker.

My suspicion is that the majority of the 500ms you've reported is actually the time taking to fetch the worker script from the server.

My recommendation is

  • Create the worker as the page loads, not just before you want to use it. (although if you're already using it as the page loads, there isn't much you can do here). See http://plnkr.co/edit/cNltJvTbLxDr2FfaCuRf?p=preview and the time for a message to get to/back from an existing worker for me is down to ~2ms.

  • Make sure the Worker javascript file is cacheable by the browser, setting appropriate HTTP headers. Therefore avoiding the network request on all but the first visit.

  • If the page with the worker isn't usually the very first page on your site that the visitor sees, you could slightly cheat and load the worker on other pages, but not use it. If the script has the appropriate caching headers, it will avoid the request on the page that actually needs it.

Alternatively, you could avoid having the worker as a separate file, and have the code inline and convert it to a Data URI, as described at https://stackoverflow.com/a/6454685/1319998 . However as noted at https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

There is currently disagreement among browsers vendors on what URIs are of the same-origin; Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0 / SeaMonkey 2.7) and later do allow data URIs and Internet Explorer 10 does not allow Blob URIs as a valid script for workers.

So I would be careful to test on browsers that you want to support.

Community
  • 1
  • 1
Michal Charemza
  • 25,940
  • 14
  • 98
  • 165
  • Thanks for your answer! I'll investigate. Do you know that `` is unnecessary? it doesn't change much in your example, but maybe .html doesn't need to fetch worker.js at all? Also I have more information and will update the question. – stallingOne May 17 '15 at 09:00
  • @user456789123 I suspect it is unnecessary, and could cause some errors since it run not in a web worker environment. (Say if it tries to access the WorkerGlobalScope object). – Michal Charemza May 17 '15 at 09:26