javascript - 替换浏览器插件中的大量文本

标签 javascript performance firefox-addon

我正在尝试开发一个 Firefox 插件,可以将任何页面上的文本音译成特定的语言。实际上它只是我迭代并使用此代码的一组二维数组

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

function replaceAll(find, replace) {
    return document.body.innerHTML.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

function convert2latin() {
    for (var i = 0; i < Table.length; i++) {
        document.body.innerHTML = replaceAll(Table[i][1], Table[i][0]);
    }
}

它有效,我可以忽略 HTML 标签,因为它只能是英文的,但问题是性能。当然是非常非常的穷。由于我没有 JS 经验,所以我尝试谷歌搜索,发现 documentFragment 可能会有所帮助。
也许我应该使用另一种方法?

最佳答案

根据您的评论,您似乎已经被告知最昂贵的事情是当您完全替换页面的全部内容时发生的 DOM 重建(即当您分配给 document.body.innerHTML )。您目前正在为每次替换执行此操作。这会导致 Firefox 为您所做的每个替换重新呈现整个页面。在完成所有替换后,您只需分配给 document.body.innerHTML 一次。

以下内容应提供使其更快的第一步:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

function convert2latin() {
    newInnerHTML = document.body.innerHTML
    for (let i = 0; i < Table.length; i++) {
        newInnerHTML = newInnerHTML.replace(new RegExp(escapeRegExp(Table[i][1]), 'g'), Table[i][0]);
    }
    document.body.innerHTML = newInnerHTML
}

您在评论中提到没有真正需要为匹配使用 RegExp,因此以下会更快:

function convert2latin() {
    newInnerHTML = document.body.innerHTML
    for (let i = 0; i < Table.length; i++) {
        newInnerHTML = newInnerHTML.replace(Table[i][1], Table[i][0]);
    }
    document.body.innerHTML = newInnerHTML
}

如果您真的需要使用 RegExp 进行匹配,并且要多次执行这些精确替换,最好在第一次使用之前创建所有 RegExp(例如,当 Table 被创建/更改)并存储它们(例如在 Table[i][2] 中)。

但是,分配给 document.body.innerHTML 是一种糟糕的方法:

如 the8472 所述,替换 document.body.innerHTML 的全部内容是执行此任务的一种非常繁重的方法,它有一些明显的缺点,包括可能破坏其他 JavaScript 的功能页面和潜在的安全问题。更好的解决方案是仅更改 textContent的文本节点。

这样做的一种方法是使用 TreeWalker .这样做的代码可能是这样的:

function convert2latin(text) {
    for (let i = 0; i < Table.length; i++) {
        text = text.replace(Table[i][1], Table[i][0]);
    }
    return text
}

//Create the TreeWalker
let treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT,{
    acceptNode: function(node) { 
        if(node.textContent.length === 0
            || node.parentNode.nodeName === 'SCRIPT' 
            || node.parentNode.nodeName === 'STYLE'
        ) {
            //Don't include 0 length, <script>, or <style> text nodes.
            return NodeFilter.FILTER_SKIP;
        } //else
        return NodeFilter.FILTER_ACCEPT;
    }
}, false );
//Make a list of nodes prior to modifying the DOM. Once the DOM is modified the TreeWalker
//  can become invalid (i.e. stop after the first modification). Doing so is not needed
//  in this case, but is a good habit for when it is needed.
let nodeList=[];
while(treeWalker.nextNode()) {
    nodeList.push(treeWalker.currentNode);
}
//Iterate over all text nodes, changing the textContent of the text nodes 
nodeList.forEach(function(el){

    el.textContent = convert2latin(el.textContent));
});

关于javascript - 替换浏览器插件中的大量文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37562475/

相关文章:

javascript - 突变通过 react-adopt 触发两次

javascript - 如何选择第一个li

javascript - 在 JS 中查询 boolean 变量与比较两个字符串

firefox-addon - 永久安装自定义的 Firefox 网络扩展 - 无需 mozilla 帐户或不稳定版本的 Firefox

javascript - mozrepl:遍历所有 firefox 窗口中的所有选项卡

javascript - 我可以检测网页中是否存在扩展程序吗?

javascript - 我的 javascript Canvas map 脚本和性能不佳

c - 任何与 pthread_getcpuclockid 等效的函数,因为我有 Thread

java - 如何优化activemq

firefox - 如何在 pagemod 和 widget 之间发出和监听事件?