【问题标题】:Best Practices For Heavy Computations in Javascript?Javascript 中重计算的最佳实践?
【发布时间】:2012-12-06 12:32:07
【问题描述】:

我正在处理客户端脚本,需要进行繁重的计算,例如在数组中推送大量对象,这会导致 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);
}

【问题讨论】:

  • 在我看来,Javascript 不应该做任何繁重的计算。繁重意味着需要大量时间的大量数据或非常困难的算法。
  • 给我们看一些代码或告诉逻辑来评论
  • 这是一个相当开放的话题。发布一些代码以使其具体化将是更好的一步。
  • 很多事情很难实现。解决办法不是找到更容易的事情,而是更加努力。
  • @ZaheerAhmed:我们可以说“避免 Massive 循环,避免 Huge 数组/对象,don't use heavy operations in each iteration of a loop, if it can be done outside of it,但所有这些都是方式为 StackOverflow Q&A 格式的通用方式。

标签: javascript design-patterns heavy-computation


【解决方案1】:

好的,看看你的代码,有几处你可以优化:

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,尤其是,如果您正在循环一个大型对象。

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

【讨论】:

  • 感谢优化,实现!!! :) 但仍然面临问题,这就是为什么我问一个通用的解决方案? -- 不错 +1
  • 我认为这 4 点几乎是我能做到的“一般”。虽然,我发现我可以再做 1 个编辑。 (chartMin /chartMax)
【解决方案2】:

你应该使用WebWorkers

他们是really supported 它们是 javascript 中的真正线程,因为它们产生真正的操作系统线程!

示例

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 !!!
}

【讨论】:

    【解决方案3】:

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

    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

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

    【讨论】:

    • 我完全清楚 JavaScript 本身没有线程,因此使用了引号。但是在这种特定情况下,将代码分成块的方法使程序一次处理 100 次迭代有效。我想我用引号和代码中的日志语句明确表示我不是在谈论真正的线程。这是我选择将其与另一种已知模式进行比较的词。如果我让任何人感到困惑,我很抱歉
    • JavaScript 不仅没有线程,而且没有任何并行执行的概念。 setTimeout 与否,不可能同时运行两个函数 - 它们将始终串行运行。所以这个解决方案除了减慢你的代码速度之外不会做任何事情。
    • 在我的回答中没有说过我的解决方案将并行执行函数。关键是退出当前正在运行的函数并以新的起始值重新开始。这里的重点是消除浏览器警告,我的示例就是这样做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 2017-05-11
    • 2012-03-03
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多