我正在尝试开发一个 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/