13

I am working on client side scripts and need to do heavy computations like pushing huge number of objects in an array, it causes JavaScript to stop response and browser hangs giving an alert:

Browser Warning

Is there any best practices or design patterns for handling these computation, I search and find many different ways to handle these situation but solutions are difficult to implement so I need best practices and easy to understand?

(I am writing code just for example But I need a general solution that is cross-browser i.e, multi-threading etc)

Example Code (series contains thousands of objects):

for (var series = 0; series < chartObj.masterChart.series.length; series++) {
    var detailData = [];
    jQuery.each(chartObj.masterChart.series[series].data, function (i, point) {
        if (point.x >= chartObj.RangeSelectedMinValue && point.x <= chartObj.RangeSelectedMaxValue) {
            detailData.push({
                x: point.x,
                y: point.y
            });
        }
    });
    chartObj.detailChart.series[series].setData(detailData);
}
13
  • 1
    In my opinion Javascript shouldn't do any heavy computation. Heavy means huge number of data or realy difficult algorithms which take a lot of time. Commented Dec 19, 2012 at 7:44
  • Show us some code or tell logic to comment Commented Dec 19, 2012 at 7:46
  • That's quite an open topic. Posting some code to make it specific would be a better step. Commented Dec 19, 2012 at 7:46
  • Many things are difficult to implement. The solution is not to find easier things but to try harder. Commented Dec 19, 2012 at 7:46
  • 2
    @ZaheerAhmed: We can say things like "Avoid Massive Loops, Avoid Huge arrays / objects, don't use heavy operations in each iteration of a loop, if it can be done outside of it, but all of that is way to generic for the StackOverflow Q&A format. Commented Dec 19, 2012 at 7:57

3 Answers 3

5

Okay, looking at your code, there's a few things you can optimize:

var s = chartObj.masterChart.series, // #1
    sLength = s.length,              // #2
    chartMin = chartObj.RangeSelectedMinValue,
    chartMax = chartObj.RangeSelectedMaxValue;
for (var series = 0; series < sLength; series++) {
    var detailData = [],
        data = s[series].data,       // #3
        length = data.length;        // #2
    for(var i = 0; i < length; i++){ // #4
        var point = data[i];
        if (point.x >= chartMin && point.x <= chartMax) {
            detailData.push({
                x: point.x,
                y: point.y
            });
        }

    }
    chartObj.detailChart.series[series].setData(detailData);
}
  1. You're getting the same "deeper" object inside chartObj multiple times --> Assign it to a temporary variable;
  2. Don't calculate the length for every iteration of the loop. Same principle as #1
  3. Assign s[series].data to a temp var. This provides a direct pointer to the data instead of having to access s[series].data each iteration of the loop. Same principle as #1
  4. jQuery is slow. For a simple loop, use JavaScript instead, especially if you're looping through a massive object.

I'm not saying this edit will work miracles, but it should reduce the load a bit.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you nice optimization, implemented!!! :) but still facing problems that is why I ask a general solution? -- Nice +1
I think those 4 points are pretty much as "general" as I can make it. Although, I found 1 more edit I could make. (chartMin /chartMax)
5

You should use WebWorkers

They are really supported and they are real threads in javascript as they spawn real OS threads!

Example

main.js

var heavy_process = new Worker('heavy_process.js');

heavy_process.addEventListener('message', function(e) {
  // Log the workers message.
  console.log(e.data);
}, false);

heavy_process.postMessage();

heavy_process.js:

for (var series = 0; series < chartObj.masterChart.series.length; series++) {

  var detailData = [];
  jQuery.each(chartObj.masterChart.series[series].data, function (i, point) {
      if (point.x >= chartObj.RangeSelectedMinValue && point.x <= chartObj.RangeSelectedMaxValue) {
        detailData.push({
            x: point.x,
            y: point.y
        });
      }
  });
  chartObj.detailChart.series[series].setData(detailData);
  // you should use self.postMessage here !!!
}

Comments

2

You could split it in to different "threads" by using timeouts. Like so:

var counter;

function longRun(start) {
    counter = 0;

    for (var i = start; i < 3000; i++) {

        counter++;
        console.log(i);
        if (counter > 99) {
            setTimeout(function() {
                longRun(i+1)
            }, 0);
                console.log('counter at: ' + i + ' start fake "thread"');
            return;
        }
    }
    alert('Done!');
}
longRun(0);​

jsFiddle example

I guess it would prevent the warning, but I don't know how sane it really is.

3 Comments

I am fully aware that there are no threads per se in JavaScript, hence the quotation marks. But in this specific case the method of splitting the code into chunks makes the program handle 100 iterations at a time works. I think I made it clear with the quotation marks and the log statement in the code that I am not talking about real threads. It was a word I choose to compare it to another know pattern. I am Sorry if I was confusing anyone
Not only does JavaScript not have threads, it has no concept of parallel execution whatsoever. setTimeout or no, it's impossible to have two functions running at the same time - they will always be run in serial. So this solution won't really do anything but slow down your code.
At no point in my answer did I say that my solution would execute functions in parallel.The point is to exit the currently running function and start again with a new start value. The main point here was to get rid of the browser warning, which my example did.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.