从 “string.replaceAll is not a function” 中复盘 JQuery.js 兼容性问题

本文复盘了一个在手机端打开博客时因JQuery.js的replaceAll方法引发的兼容性问题,导致页面加载失败。通过手机端调试发现,异常发生在replaceAll方法,可能由于浏览器内核兼容性。解决方案是使用replace和正则表达式实现replaceAll的功能,同时修正了主题中的正则表达式误匹配问题,避免了行内公式识别错误。总结强调在使用第三方库和正则表达式时应注意兼容性和精确匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析

意外发现博客的某篇文章在手机端打开的时候一直处于加载中的状态,但是点开其他文章却又是正常的,推断可能是前端页面在渲染的过程中遇到某些错误被中断了。

chrome 浏览器直接打开 mobile 模式还是能正常显示,无法完全模拟手机端的情况

复现

由于手机端的浏览器无法直接进行调试,需要通过 usb 连接到电脑,再使用 chrome 浏览器结合 pc 和手机端进行调试。

手机端调试接入的方式参考:

https://blog.youkuaiyun.com/weixin_32149443/article/details/112936241

这篇博文是转载的,且格式杂乱无章。。csdn的水文真是越来越多了,原文是 cnblog 的一篇文章,但是已经无法显示了,将就着看吧。

接入调试后发现,是文章内容在渲染的时候 jquery.js 抛出了错误,导致内容的渲染被中断了。

image.png

点进错误信息里面我们可以看到异常发生的具体是哪行代码,如下图

image.png

从上图的第二处可以看出,抛出异常的是 formatMath 这个方法,从注释和代码上来看,这个方法的具体作用可能是对文章内容中出现的一些公式做处理。

前期推测可能是传入的某一次循环中传入的 kateBlock 值为 null 对象,导致无法调用 replaceAll 方法(该方法只有在字符串类型时才存在),也就是 Java 中经常遇到的空指针异常(没有在使用某个对象前对其值为空的情况做出处理)只是在 js 体现的不一样。

在渲染别的文章内容时基本没有触发引用 dealMathx 这个方法,所以这个问题也没有被发现。

解决

stackoverflow 这篇文章中得知,有可能是浏览器内核对 replaceAll 这个方法的兼容性问题导致的。

本篇文章中的安卓 chrome 版本是 78.x,而不在官方给到的支持版本范围内,如下图

image.png

image.png

到这里我们知道 replaceAll 这个 js api 可能会出现浏览器兼容性问题,是否有其他代替方案?

使用 RegExp 结合 replace 实现 replaceAll 的效果,实现更好的兼容性。

编写一个 escapeRegExp 方法,将部分字符进行转义,返回一个合法的正则表达式字符串

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

自定义 replaceAll

function replaceAll(str, match, replacement){
   return str.replace(new RegExp(escapeRegExp(match), 'g'), ()=>replacement);
}

修改 Xue 主题 main.js 中的 formatMath 方法,将原有的 replaceAll 替换为我们自定义的 replaceAll

/**
 * 格式化公式
 */
function formatMath(kateBlock, isBlock) {
    // 这一步很重要,需要把 & 换成 &
    //var block = kateBlock.replaceAll("&", "&");
    var block = replaceAll(kateBlock,"&", "&")
    if (block.length < 3) {
        return;
    }
    // ... ... 
}

修改即可正常渲染文章的内容(可以使用 halo 自带的主题编辑功能进行测试)

image.png

正则表达式 “误判” 的问题

Halo 博客的 Xue 主题中的 main.js 内用于识别 行内公式 正则表达式错误的匹配到了我文章的内容,并进行了替换,导致文章内容显示异常。

main.js 内的源码:

image.png

正则匹配测试

image.png

渲染错误的效果

image.png

我们来复盘一下这条正则表达式:/\$([\s\S]*?)\$/g

其意义是在字符串全局范围内,匹配以 $ 号开头以及结尾,中间的内容为多个空格或者非空字符(几乎包含了任意字符)

平时很少用 markdown 去写一些公式,所以去查了一下语法,其特征确实是以两个 $ 号来标识为一个公式

image.png

正好这篇文章的 markdown 中有两段内容包含了 ${} 用作 freemarker 的变量,导致内容在渲染出来后被前端替换

image.png

解决方案:

  • 将匹配行内公式的正则表达式中的 [\s\S]*? 替换为 .*? 实现匹配任何非换行符的字符。

    正因为是行内公式,所以也不需要匹配换行符,合情合理。。

  • 且需要考虑文章内也出现包含 \$xxx\$ 的正则表达式的情况

所以最终将 /\$([\s\S]*?)\$/g 替换为 /\$(?!\\$)(.*?)\$(?!\\$)$/g

  • 这里用到了正则表达式中的 负向先行断言 的概念,例如 exp1(?!exp2) 中正则 exp1 匹配的内容需要在正则 exp2 中不成立,想进一步的学习该内容可以参考 这篇文章,这里不就不过多的赘述。

  • 这个问题也间接的让本篇文章所提到的 replaceAll 这个 api 兼容问题浮出了水面 🤣

总结

  • 在使用第三方库(例如 JQuery.js)时,尽可能使用更兼容型的 api 去实现需求。

  • 在使用正则表达式对某些内容最匹配时,尽可能更多的特征条件,避免错误的匹配。

  • 浏览器会缓存js文件,在修改后,最好先清空缓存,或打开控制台 network 勾选 Disable cache 在进行测试。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值