Search code examples
javascriptxmlhttprequestweb-worker

web worker containing xhr object with upload progress event handler


I'm trying to create a worker that uploads file attached with event handler that will update progress bar in my html page. the upload is already working fine in the worker.

I know that web worker has no access to DOM objects, which is where all my progress bars are. so, I'm wondering if there's any work around? I want to do the uploads in worker, but I also want the progress tracking. I'll be uploading several file in parallel, so, each worker (upload) will have its own progress bar. is this doable? or should I let go of web worker altogether and choose different design?

this is what's inside my worker

onmessage = e => {
        var xhr = new XMLHttpRequest();
        xhr.addEventListener('progress', function(e) {
            var done = e.position || e.loaded, total = e.totalSize || e.total;
            console.log('xhr progress: ' + (Math.floor(done/total*1000)/10) + '%');
        }, false);
        if ( xhr.upload ) {
            xhr.upload.onprogress = function(e) {
                var done = e.position || e.loaded, total = e.totalSize || e.total;
                console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
            };
        }
        xhr.onreadystatechange = function(e) {
            if ( 4 == this.readyState ) {
                console.log(['xhr upload complete', e]);
            }
        };
        xhr.open('post', url, true);
        xhr.setRequestHeader("Content-Type","multipart/form-data");
        let formData = new FormData();
        formData.append("thefile", e.data.payload);
        xhr.send(formData)
}

I already prepared some event handler, but currently, it's just logging.

Thanks


Solution

  • The onmessage events includes a .source property. This is how you send data back to the client. Inside your progress event listener you would add something like:

    e.source.postMessage({uploadName: <unique name>, progress: done});
    

    Watch out, though. You use e as both the onmessage handler data and the progress event handler. I would recommend making the names of the two unique.

    Then in your page you listen for the message:

    window.addEventListener('message', (data) => {
      // ... read data.progress and send it to the right place on the page
    }