JavaScript非全局正则exec调用触发无限循环致浏览器崩溃问题
正则触发无限循环的原因说明
核心原理:JS正则exec()方法的行为差异
JavaScript中正则对象调用exec()方法的行为,完全受g(全局)标志控制:
- 带
g标志的正则,会在自身维护一个lastIndex属性,记录下次匹配的起始位置。每次匹配成功后,lastIndex会自动更新到当前匹配内容的末尾;如果后续找不到匹配项,lastIndex会被重置为0,同时exec()返回null。 - 不带
g标志的正则,不会维护lastIndex属性,无论调用多少次exec(),永远从输入字符串的起始位置开始匹配。
死循环触发逻辑
你的循环终止条件用了逗号运算符,最终判断是否继续循环的依据只有最后一个表达式的结果:(skuToken = sku.exec(specSheet)) !== null。
由于你给sku正则只加了m(多行)标志、没有加g标志:
- 只要输入文本里存在符合sku规则的内容,每次调用
sku.exec(specSheet)都会固定返回第一个匹配结果,永远不会返回null - 循环条件永远为真,没有任何终止时机,会无限重复执行do块内的输出逻辑,最终占满内存导致页面崩溃。
加/mg标志后正常运行的原因
给sku正则加上g标志后,每次调用exec()都会向后移动lastIndex指针,扫完整段文本找不到新的匹配项时就会返回null,循环可以正常终止。但此时会匹配输出所有符合规则的sku,不符合你仅取第一个结果的需求。
修正方案
你不需要把仅需首个匹配的sku规则放到循环里:
- 对需要提取所有匹配结果的规则(比如
wallMountable),保留循环遍历逻辑即可 - 对仅需第一个匹配结果的规则(比如sku),在循环外执行一次
exec()拿到结果直接使用,不要放到循环条件中反复执行。
修正后的核心代码参考:
let wallMountable = /(?<wallmountable>[Ww]all [Mm]ount)/mg; let sku = /^.*\((?<sku>\d\d\w\w[\d\w]+?).+?\).*$/m; function parseData() { let specSheet = document.getElementById("specSheet").value; // 仅取第一个sku匹配结果,无需进入循环 let skuToken = sku.exec(specSheet); if (skuToken !== null && skuToken.groups.sku !== undefined) { document.write(`${skuToken.groups.sku}`); } // 只遍历需要提取所有匹配项的规则 let wallMountableToken; while ((wallMountableToken = wallMountable.exec(specSheet)) !== null) { if (wallMountableToken.groups.wallmountable !== undefined) { document.write(`${wallMountableToken.groups.wallmountable}`); } } }
额外提示:你原本写的do-while结构本身也存在逻辑缺陷,逗号运算符会直接忽略前半部分
wallMountable.exec()的返回结果,哪怕wallMountable已经遍历完所有匹配,只要sku能匹配到,循环依然不会停止。
内容的提问来源于stack exchange,提问作者RapidScampi
相关产品推荐
相关产品推荐

