Question

I have a web worker that I'm using to poll for information.

Here is the code for starting and stopping the web worker:

var eftWorker = undefined;

that.StartWorker = function () {
    if (eftWorker === undefined) {
        eftWorker = new Worker('../scripts/ETEL.EftWorker.js');
        eftWorker.addEventListener('message', function(e) {
            EftWorkerResponseHandler(e.data);
        }, false);
        eftWorker.addEventListener('error', function(e) {
            EftWorkerErrorResponseHandler(e);
        }, false);
    }

    eftWorker.postMessage({ cmd: eftCmdStart });
};

that.StopWorker = function () {
    if (eftWorker !== undefined) {
        eftWorker.postMessage({ cmd: eftCmdStop });
        eftWorker.terminate();
    }
    eftWorker = undefined;
};

When I call terminate on the worker, because the worker is polling there seems to be a backlog of unprocessed postmessage events.

I'm setting the web worker to "undefined" on initialisation of the containing view and on termination of the web worker. I believe because of the latter, those unprocessed events are shown as ABORT_ERRORs. Is there an intermediate state that I can use to test the existence of the web worker so that I can allow it to process the outstanding events and therefore avoid the errors?

Or is there a different approach that I might use to avoid the accumulation of errors after terminate is called?

Was it helpful?

Solution

Here is my solution to the problem.

I'm recording the state of the worker in a separate variable in order that I can keep it alive to handle the outstanding messages that are causing the errors.

Also I'm trapping and discarding any errors generated inside the worker itself.

var eftWorker = undefined;
var eftWorkerState = undefined;

var workerStateStarted = 'started';
var workerStateStopped = 'stopped';

var StartWorker = function () {
    if (eftWorker === undefined | eftWorkerState !== workerStateStarted) {
        eftWorker = new Worker('/scripts/ETEL.EftWorker.js');
        eftWorker.addEventListener('message', function(e) {
            EftWorkerResponseHandler(e.data);
        }, false);
        eftWorker.addEventListener('error', function (e) {
            EftWorkerErrorResponseHandler(e);
        }, false);
    }

    eftWorker.postMessage({ cmd: eftCmdStart });
    eftWorkerState = workerStateStarted;
};

that.StopWorker = function () {
    if (eftWorker !== undefined) {
        eftWorker.postMessage({ cmd: eftCmdStop });
        eftWorker.terminate();
    }
    eftWorkerState = workerStateStopped;
    //eftWorker = undefined;
};

var EftWorkerResponseHandler = function (msg) {
    try {
        if (eftWorkerState === workerStateStarted) {
            if (msg != '' && msg !== undefined) {
                var parser = new DOMParser();
                var xmlDoc = parser.parseFromString(msg, 'text/xml');

                var json = $.xmlToJSON(xmlDoc);

                AlterPaymentUIAccordingToEftWorkerStatus(json);
            }
        }
    } catch (exception) { }
};

And here's the code from the worker responsible for sending back the status messages.

EftSendGetRequest = function(passedUrl) {

    if (xmlHttpReq === undefined) {
        xmlHttpReq = new XMLHttpRequest();
    }

    try {
        xmlHttpReq.open("GET", passedUrl, false);
        xmlHttpReq.send();
    } catch (e) { }

    return xmlHttpReq.responseText;
};

OTHER TIPS

This is old but I was looking at it while searching for a different answer..

Why not let the worker handle its own state and termination? The original question asks how to let the worker finish outstanding requests. So let it finish its requests and indicate when it is done.

If the javascript was something like this:

var eftWorker = undefined;

var StartWorker = function () {
    if (eftWorker === undefined) {
        eftWorker = new Worker('/scripts/ETEL.EftWorker.js');
        eftWorker.addEventListener('message', function(e) {
            EftWorkerResponseHandler(e.data);
        }, false);
        eftWorker.addEventListener('error', function (e) {
            EftWorkerErrorResponseHandler(e);
        }, false);

        // i'm assuming we don't want to trigger start multiple times,
        // so this is moved inside the IF.
        eftWorker.postMessage({ cmd: eftCmdStart });
    }
};

that.StopWorker = function () {
    if (eftWorker !== undefined) {
        eftWorker.postMessage({ cmd: eftCmdStop });
    }
};

var EftWorkerResponseHandler = function (msg) {
    try {
        if (msg && msg === 'readyToTerminate') {
            eftWorker.terminate();
            eftWorker = undefined;
        } else {
            // handle other situations.
        }
    } catch (exception) { }
};

and the worker was like this:

;(function(self, undefined) {
    var receivedStopCmd = false;

    self.addEventListener('message', function(e){
        if (e.data.cmd === 'eftCmdStart') {
            // kick off processing here
            EftSendGetRequest('...');
        }

        if (e.data.cmd === 'eftCmdStop') {
            // xhr might be in process, this just updates what
            // the onload function does.
            receivedStopCmd = true;
        }
    }, false);


    var EftSendGetRequest = function(passedUrl) {

        if (xmlHttpReq === undefined) {
            xmlHttpReq = new XMLHttpRequest();
        }

        try {
            xmlHttpReq.open("GET", passedUrl, false);
            xmlHttpReq.onload = function(){
                if (!receivedStopCmd) {
                    // post response and/or keep polling
                    self.postMessage('whatever the message is');
                } else {
                    // (1) stop polling so no more 
                    //     requests are sent..if this 
                    //     requires doing anyhting

                    // (2) Send a message that this worker can be terminated.
                    self.postMessage('readyToTerminate');
                }

            };
            xmlHttpReq.send();
        } catch (e) { }

        return xmlHttpReq.responseText;
    };
})(self);

This would allow the XHR to manage itself. I didn't run this of course.. its just an example of the approach I would take on the question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top