1

I'm very new in js, I'm working on project for wingsuit pilots (track analyzer).

On page I implement range selector and few charts, so user can select which part of data he want to analyze.

Problem is - sometime user change range from both frontiers, so in that case he waits when finish first calculation and second.

Question is - is there any way to stop execution block of code if user iterate with range slider? I'll be very appreciate for directions to approach this task.

you can visit this page and try it for better understanding - try to change range twice without wait for charts and data update.

EDIT: When user finish with range slider it calls callback function, where I implemented calculations and charts update. Range selector also has onChange callback. So is there any way to stop execution one function from another one? Or may be I should call same function with parameter and do something?

Range slider initializing:

  $(document).ready(function() {

    $("#range_selector").ionRangeSlider({
      min: max_height,
      max: 0,
      type: 'double',
      step: 50,
      prettify: false,
      hasGrid: true,
      from: max_height,
      to: 0,
      onFinish: function (obj) {      // callback is called on slider action is finished
        range_from = obj.fromNumber;
        range_to = obj.toNumber;
        set_chart_data();
      }
    });

Here is computing loop:

    for (var index in charts_data) {

      var current_point = charts_data[index];
      var point = {};

      isLast = true;

      if (current_point.elevation <= max_val && current_point.elevation >= min_val) {

        point = clone(current_point);

        // Корректировка выбранного диапазона
        if (isFirst) {

          isFirst = false;
          if (current_point.elevation != max_val && charts_data.hasOwnProperty(index-1)) {

            point.elevation_diff = max_val - current_point.elevation;

            var k = point.elevation_diff / current_point.elevation_diff;

            point.distance = Math.round(current_point.distance * k);
            point.fl_time = Math.round(current_point.fl_time * k);
          }
        }

        isLast = false;

        dist += point.distance;
        elev += point.elevation_diff;

        elev_data.push([fl_time, Math.round(elev)]);
        dist_data.push([fl_time, dist]);

        heights_data.push([fl_time, Math.round(point.elevation)]);
        h_speed.push([fl_time, point.h_speed]);
        v_speed.push([fl_time, point.v_speed]);

        gr.push([fl_time, point.glrat]);

        fl_time += point.fl_time;

        min_h_speed = min_h_speed == 0 || min_h_speed > point.h_speed ? point.h_speed : min_h_speed;
        max_h_speed = max_h_speed == 0 || max_h_speed < point.h_speed ? point.h_speed : max_h_speed;

        min_v_speed = min_v_speed == 0 || min_v_speed > point.v_speed ? point.v_speed : min_v_speed;
        max_v_speed = max_v_speed == 0 || max_v_speed < point.v_speed ? point.v_speed : max_v_speed;

        min_gr = min_gr == 0 || min_gr > point.glrat ? point.glrat : min_gr;
        max_gr = max_gr == 0 || max_gr < point.glrat ? point.glrat : max_gr;
      }

      if (isLast && elev_data.length > 0) {
        if (current_point.elevation <= min_val && charts_data.hasOwnProperty(index - 1)) {

          point = clone(current_point);
          prev_point = charts_data[index - 1];

          point.elevation_diff = prev_point.elevation - min_val;
          var k = point.elevation_diff / current_point.elevation_diff;

          point.fl_time = current_point.fl_time * k;
          point.elevation = min_val;
          point.distance = Math.round(current_point.distance * k);

          dist += point.distance;
          elev += point.elevation_diff;

          elev_data.push([fl_time, Math.round(elev)]);
          dist_data.push([fl_time, dist]);

          heights_data.push([fl_time, Math.round(point.elevation)]);
          h_speed.push([fl_time, point.h_speed]);
          v_speed.push([fl_time, point.v_speed]);

          gr.push([fl_time, point.glrat]);
        }
        break;
      }
    }
Aleksandr K.
  • 1,338
  • 14
  • 21
  • 1
    You might want to check this : http://stackoverflow.com/questions/672732/prevent-long-running-javascript-from-locking-up-browser – naota Jul 11 '14 at 12:59
  • @naota: That question is about 5 years old... JS has changed quite a bit since then. Not in the least, the addition of the `Worker` API, which is a much, much better fit for problems like these – Elias Van Ootegem Jul 11 '14 at 13:01
  • @EliasVanOotegem, I quite agree with you. Your answer is excellent. I just put the link to show there is an old history and wisdom for this problem. I should have written so. And I guess some developper have to deal with old browsers or mobile browsers which don't support the workers. http://caniuse.com/webworkers – naota Jul 11 '14 at 13:11

1 Answers1

3

Note:
I haven't looked at your link, simply because I'm being cautious. You probably should set up a fiddle, and you certainly should add a minimal code sample to your question. A link alone is not enough.

The short answer is no.

JavaScript is single threaded. It runs in one thread in the browser, and so any code that responds to any action (taken by the user or a piece of code) can't run until the engine has finished doing whatever it is doing at any given time.
When a function is called, the only things that can stop that function from running are: syntax errors, the browser (script is taking too long, browser can kill it), or the function returns (finishes normally). No function can be called when one function is working. Concurrency is impossible. Whatever event listeners you have, the callbacks will be queued, only to be invoked once the function has returned.

There is some good news, though. If the computation really takes, like you say 1 second, then you can create a worker. You can fork off the heavy work to this worker, and add an event listener to the instance, that listends for messages. Write the worker so that, when it is done, it sends a message back to the man JS thread. While the worker is running, the main JS thread can carry on freely.

To stop a worker while it's busy performing some complex computations, you simply invoke the terminate method:

(function()
{
    var w = new Worker('worker/code/script.js'),
        handler = function()
        {
            w.terminate();
        },
        btn = document.querySelector('#stopBtn');
    btn.addEventListener('click', handler, false);
    w.onmessage = function(e)
    {
        btn.removeEventListener('click', handler, false);//listener not needed anymore
        console.log('Worker finished, its response was: ', e.data);
        this.terminate();//kill worker
    };
    //init worker
    w.postMessage('Data to pass to worker here');
}());
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • Thanks so much! It is what I was looking for. I didn't set fiddle because of my question is abstract and about directions not about code something. I paste link only with one reason - if I said something incorrect (because of my English) - web page shows it more clear. – Aleksandr K. Jul 11 '14 at 12:57
  • I've added code samples. Not sure it makes my question more clear, but better than nothing – Aleksandr K. Jul 11 '14 at 13:08