2

我正在使用该函数replaceStr()替换正文标记中的一些字符串。如果 html 页面很小,则替换不明显。但是如果 html 页面更大更复杂,你会注意到它。替换正在阻止浏览器。我的问题,如何使替换非阻塞?替换对页面并不重要,因此它可以在浏览器不忙时在后台发生。我尝试使用asyncawait,但我认为该replaceWith()函数无法处理 Promises,这就是它不能与async/await一起使用的原因。但是你怎么能做到呢?

function replaceStr(myStrArr) {
  const container = $('body :not(script)');
  myStrArr.map((mystr) => {
    container
      .contents()
      .filter((_, i) => {
        return i.nodeType === 3 && i.nodeValue.match(mystr.reg);
      })
      .replaceWith(function () {
        return this.nodeValue.replace(mystr.reg, mystr.newStr);
      });
  });
}

感谢您的帮助。

4

1 回答 1

2

您当前的实现有几个地方可以在进行异步路由之前进行优化。例如,您可以摆脱jQuery依赖。它对您的情况没有多大帮助,但会增加开销。

然后,目前您正在映射您的替换,并为所有候选节点上的每个节点进行映射,每次都替换nodeValue。这可能会触发每次重绘。

相反,您可以使用 aTreeWalker快速迭代相关节点,并且只更新nodeValues一次。


在我的测试中,以下代码的运行速度大约比您当前的代码快 16 倍。也许这已经足够了?

function replaceStr_upd(replacements) {
    // create a tree walker for all text nodes
    const it = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
        // but skip SCRIPTs
        acceptNode: node => node.parentNode.nodeName === 'SCRIPT'
                            ? NodeFilter.FILTER_REJECT
                            : NodeFilter.FILTER_ACCEPT
    });

    // a helper function
    const applyReplacements = initial => replacements.reduce((text, r) => text.replace(r.reg, r.newStr), initial);

    // iterate over all text node candidates
    while (it.nextNode()) {
        // but only update once per node:
        it.currentNode.nodeValue = applyReplacements(it.currentNode.nodeValue);
    }
}
于 2020-07-20T12:59:36.407 回答