0

I have below code in main.html

if(typeof(Worker) !== "undefined") {
        if(typeof(w) == "undefined") {
            w = new Worker("/location_worker.js");
        }
        w.onmessage = function(event) {
        sequence = event.data;
        if(Cookies.get("location_tracked") == "done")
        {
            w.terminate();
            w = undefined;
            return;
        }
        if(navigator.geolocation)
        {
            navigator.geolocation.getCurrentPosition(function(position)
            {
                lat = position.coords.latitude;
                lon = position.coords.longitude;
                $.ajax({
                  type: "POST",
                  url: "/api/",
                  data: {'action':'receive_loc', 'lat': lat,'lon': lon,'enc_data': enc_data,'reached': reached , 'sequence' : sequence },
                  success: function(jres)
                  {
                    res = JSON.parse(jres);

                    stop = false;

                    if(res.status == 11)
                    {
                        stop = true;
                    }


                    if(!stop)
                    {
                        //loop continues
                    }else{
                        finished = true;
                        w.terminate();
                        w = undefined;
                        return;
                    }
                  },
                });
            },function(code, message) {
                $('#error').html("<b>Location Sharing blocked by User..</b>");
            });


        } else{
            alert("Sorry, your browser does not support HTML5 geolocation.");
        }

        };
    } else {
        document.getElementById("result").innerHTML = "Sorry, your browser does not support Web Workers...";
    }

And the location_worker.js contains below

var i = 0;
var ft = 2000;
function timedCount() {
    i = i + 1;
    self.postMessage(i);
    console.log(i);
    setTimeout("timedCount()",ft);
}
timedCount();

so for every 2 seconds the ajax will be submitted which is working fine but in below scenarios its not working as expected

for example if sequence 1 and 2 worked fine and tab/browser got inactive and after sometime if i return back to the this page, all the subsequent requests (which are supposed to be sent when tab is inactive) are getting sent at same time (sequence 3,4,5,6,7,8,9 etc).so all these requests are sending same data with same lat lon values which is not supposed to be happened.

someone please let me know what is wrong with this flow.

ɹɐqʞɐ zoɹǝɟ
  • 4,342
  • 3
  • 22
  • 35

1 Answers1

1

Your code gets throttled when the tab doesn't have focus. If you want to ensure you don't make two calls within two seconds of one another, use Date.now to track when you did your last call and don't do another call if it's within 2000 of the current Date.now. E.g., just outside your message handler:

var nextAllowed = Date.now();

then just inside it:

if (Date.now() < nextAllowed) {
    return;
}
nextAllowed = Date.now() + 2000;

A few things I happened to notice about that code you might want to consider changing:

  • There's no point to that web worker at all, just put that timer loop in your main page's code.
  • typeof isn't a function, there's no need to wrap its operand in ().
  • Don't pass strings into setTimeout, pass in a function reference instead. So: setTimeout(timedCount, ft);
  • Unless you have var declarations you haven't shown, your code is falling prey to what I call The Horror of Implicit Globals. Declare your variables (like w, sequence, etc.).
  • If your /api/ endpoint correctly identified the Content-Type of the response, you wouldn't have to use JSON.parse in the ajax callback. In general, try to ensure responses are sent with the correct Content-Type heder.
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thanks for the help, but when the tab is inactive how to make those subsequent requests sent in background ? what changes should i make in my code – ɹɐqʞɐ zoɹǝɟ May 29 '18 at 11:37
  • @ɹɐqʞɐzoɹǝɟ - You can't control what the browser does with your code when your tab doesn't have focus. It seems like you're trying to track the user's movements even when your tab doesn't have focus. I doubt you can. You can't use `navigator.geolocation` in a web worker, so even if the browser didn't throttle the worker (which it very well may), you still have to rely on the main thread (which may get throttled). See also: https://stackoverflow.com/questions/11533838/ (which shows a better way to do this than `setTimeout`, but which still has the same problem with being throttled). – T.J. Crowder May 29 '18 at 11:48
  • There is actually a way around the throttling: https://stackoverflow.com/questions/40687010/canvascapturemediastream-mediarecorder-frame-synchronization/40691112#40691112 (though it will probably not work if the browser itself is not focused, and will certainly not work if the device is in sleep mode) – Kaiido May 29 '18 at 12:41
  • @Kaiido - Cute. :-) Only in Chrome, though? (Seems to work in my desktop Firefox, no idea about mobile versions...) And I do wonder if tricks like this will get shut down, as so many other tricks have in the past... – T.J. Crowder May 29 '18 at 12:44
  • @T.J.Crowder This example actually revealed a lot of bugs in both Chrome and FF, but not really related with the Timer itself, more with the MediaRecorder and canvas paintings. And yes, I'm afraid it won't work forever, but since they have to maintain AudioContext's Worklet rate, I guess it should be fine. – Kaiido May 29 '18 at 12:50