循环遍历大字典的Javascript会产生无响应的脚本

时间:2014-03-24 02:50:49

标签: javascript dictionary firefox-addon

我正在创建一个firefox插件,用html文本中的其他单词添加单词。这段代码有效,但是当迭代一本巨大的字典时,我得到了一个没有响应的脚本错误。

提高此循环速度的最佳方法是什么?

将字典拆分成较小的对象?或设置timeout function

var brands = {"manykeys" : "manyvalues"};

function replaceWord(){
    for (var key in brands){
        htmlreplace(key, key + " (" + brands[key] + ")");
    }
}
function htmlreplace(a, b, element) {    
    if (!element) element = document.body;    
    var nodes = element.childNodes;
    for (var n=0; n<nodes.length; n++) {
        if (nodes[n].nodeType == Node.TEXT_NODE) {
            var r = new RegExp(a, 'g');
            nodes[n].textContent = nodes[n].textContent.replace(r, b);
        } else {
            htmlreplace(a, b, nodes[n]);
        }
    }
}

replaceWord();

3 个答案:

答案 0 :(得分:0)

我没有尝试过,但这样做可能会有效:

function replaceWord(){
    for (var key in brands){
        (function(key) {
            setTimeout(function() {
                htmlreplace(key, key + " (" + brands[key] + ")");
            }, 0);
        })(key);
    }
}

我们的想法是,当浏览器有时间推迟替换时,而不是整体地进行替换,并使浏览器在思考时冻结。

答案 1 :(得分:0)

需要考虑一些因素。这取决于你能改变什么。您可以做的更大改进之一是使用数组而不是键/值对象。

var brands = [
['manykeys0000','manyvalues0000'],
['manykeys0001','manyvalues0001'],
['manykeys0002','manyvalues0002'],
['manykeys0003','manyvalues0003'],
['manykeys0004', ...
];

function replaceWord(){
    var i, n = brands.length;
    for (i = 0; i < n; ++i) {
        htmlreplace(brands[i][0], brands[i][0] + " (" + brands[i][1] + ")");
    }
}

其他一些变化也应该有一点改进:

1。)将nodes.length移到循环外面 2.)如果合适的document.body来自replaceWord()

var body = document.body;

...
    htmlreplace(brands[i][0], brands[i][0] + " (" + brands[i][2] + ")", body);

function htmlreplace(a, b, element) {    
    var nodes = element.childNodes, len = nodes.length;
    for (var n=0; n < len; ++n) {

Chrome和Firefox的快速基准测试结果使速度提高了30-40%。


要测试的其他修改:

var r = new RegExp(a, 'g');移至replaceWord(),并将其作为第一个参数传递给htmlreplace()而不是a

function replaceWord(){
    var i, n = brands.length;
    for (i = 0; i < n; ++i) {
        var r = new RegExp(brands[i][0], 'g');
        htmlreplace(r, brands[i].join(' (') + ')', elem);
    }
}

如果你玩超时this article可能会有兴趣。它使用

window.postMessage();

实施自定义setZeroTimeout(),但不确定它会如何影响您的情况。

JSPerf等旁边使用浏览器中的分析工具,例如in Chrome,这可能更适合您在代码中执行的操作。

答案 2 :(得分:0)

代码中的瓶颈不是字典大小,除非它真的很大,但DOM遍历。

获取文本节点一次,然后使用它们。

var textnodes = $x("//text()", document.body)

function $x(p, context) {
  if (!context) context = document;
  var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item);
  return arr;
}

你应该看到相当大的速度提升。