Javascript在大字典中循环生成无响应的脚本

Javascript looping through large dictionary yields unresponsive script

本文关键字:响应 脚本 循环 字典 Javascript      更新时间:2023-09-26

我正在制作一个firefox插件,在html文本中添加单词和其他单词。这段代码可以工作,但是当遍历一个巨大的字典时,我得到一个无响应的脚本错误。

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

将字典拆分为更小的对象?或者设置一个超时函数?

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

有一些需要考虑的问题。这在很大程度上取决于你能改变什么。你可以做的一个更大的改进是使用数组而不是键/值对象。

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)。如适宜,由replaceWord()document.body

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

如果你玩超时,这篇文章可能会感兴趣。它使用

window.postMessage();

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

除了JSPerf等,在浏览器中使用分析工具,例如在Chrome中,这可能更适合你在代码中做的事情。

我还没有试过,但这样做可能会起作用:

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

这个想法是你推迟替换当浏览器有时间,而不是做它的单一和使浏览器冻结,而它正在思考。

代码中的瓶颈不是字典的大小,除非它真的很大,而是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;
}

您应该会看到相当大的速度提高。