12

我正在处理客户端脚本,需要进行大量计算,例如在数组中推送大量对象,这会导致 JavaScript 停止响应并且浏览器挂起并发出警报:

浏览器警告

是否有处理这些计算的最佳实践或设计模式,我搜索并找到了许多不同的方法来处理这些情况,但解决方案难以实施,所以我需要最佳实践并且易于理解?

(例如,我正在编写代码但我需要一个跨浏览器的通用解决方案,即多线程等)

示例代码(系列包含数千个对象):

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);
}
4

3 回答 3

5

好的,看看你的代码,你可以优化一些东西:

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. 您在 chartObj 中多次获得相同的“更深”对象 --> 将其分配给临时变量;
  2. 不要为循环的每次迭代计算长度。原理与#1相同
  3. 分配s[series].data给一个临时变量。这提供了指向数据的直接指针,而不必访问s[series].data循环的每次迭代。原理与#1相同
  4. jQuery 很慢。对于简单的循环,请改用 JavaScript,尤其是在循环一个大对象时。

我并不是说这个编辑会创造奇迹,但它应该会减少一点负载。

于 2012-12-19T08:04:53.247 回答
4

你应该使用WebWorkers

它们确实受到支持 ,并且它们是 javascript 中的真正线程,因为它们产生真正的 OS 线程!

例子

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();

重进程.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 !!!
}
于 2016-02-22T18:40:56.593 回答
2

您可以使用超时将其拆分为不同的“线程”。像这样:

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 示例

我想它会阻止警告,但我不知道它到底有多理智。

于 2012-12-19T08:26:24.923 回答