【问题标题】:How can I make jQuery replaceWith() "non-blocking" (async)?如何使 jQuery replaceWith() “非阻塞”(异步)?
【发布时间】:2020-11-09 16:12:37
【问题描述】:

我正在使用函数replaceStr() 来替换body 标签中的一些字符串。如果 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);
      });
  });
}

感谢您的帮助。

【问题讨论】:

  • 您是否尝试将async 添加到函数定义中,例如async function replaceStr(myStrArr)...???
  • @UmairKhan 这是我做的第一件事。仍然阻塞。
  • @UmairKhan 当所有方法都同步时,使用async 毫无意义
  • @charlietfl 不,因为它正在操纵 DOM?

标签: javascript jquery async-await asynchronous-javascript


【解决方案1】:

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

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

相反,您可以使用TreeWalker 快速迭代相关节点,并且只更新一次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);
    }
}

【讨论】:

  • 圣摩西耀西,你很受打击。密码……我的脑袋炸了。好的,我有很多要阅读和理解的东西,非常令人印象深刻。如果我需要排除“:not(a):not(.myClass)”之类的其他内容,该怎么办?然后我可以简单地添加一个或类似“ node.parentNode.nodeName === 'SCRIPT' || node.parentNode.nodeName === '.myClass' ”吗?
  • 哦,最后一个问题,如果我想用一些 html 代码(如 someWord 替换一个词,此解决方案是否也有效?还是只能替换纯文本?
  • @Oliver 首先,我建议彻底阅读有关tree walkers 的文档,但是是的,您只需要根据需要更新acceptNode 方法以适当地返回reject/accept。尽管如果太复杂,将整个创建逻辑提取到辅助方法中可能是有意义的。关于您的第二个问题:目前您只能传入纯文本,因为在文本节点上设置nodeValue 就像在任何其他节点上设置textContent 一样。但是您也可以简单地在父节点上设置innerHTML
  • 一个非常好的和快速的方法来替换纯文本。但是如果我想用 html 替换一个单词,它对我不起作用。 1. 它也替换了 中的文本。 2. 如果我有 A 和 A++ 并且想在它们周围添加例如 span 标签,那么你最终会得到 A++。因为它只遍历一次内容,所以它不知道第一个跨度。但仍然非常令人印象深刻的代码。所以我仍然需要以某种方式改进我的原始代码:/
  • @Oliver 好的,我理解您的问题,但是明智地跨标签边界替换内部文本是完全不同的游戏。这样做而不在途中搞砸你的 html 比简单的文本替换要复杂得多。我相信这个网站上有很多关于这个主题的问题和答案。
猜你喜欢
  • 2018-04-06
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 2015-08-03
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多