Lodash truncate 一直不返回,separator 正则可能零宽匹配
Lodash 4.18.1 的 truncate 正则循环遇到空匹配可能不推进 lastIndex。按文本需求采用字符串或明确消耗字符的分隔条件,不在服务线程中执行死循环回归。
_.truncate() 调用后一直不返回,Node 进程的一条线程持续忙碌,而输入字符串并不长。若 options.separator 使用了可能零宽匹配的正则,先撤下这条截断路径,避免在服务请求中反复重现阻塞。
Lodash 4.18.1 的一个具体触发模式是 /(?<=,)\s*/。它在逗号后的空白长度为零时仍能匹配,却不消耗字符。用于展示故障的调用形态如下,不适合直接放进在线服务做探测:
const text = 'a,b' + 'X'.repeat(200);
const options = {
length: 30,
separator: /(?<=,)\s*/,
};
// 受影响版本对这组 text/options 调用 _.truncate 可能不返回。
正则循环没有推进零长度匹配
4.18.1 的正则分隔分支会把非全局正则转换成全局形式,再反复调用 exec() 找最后一个分隔位置。对于空匹配,循环没有主动推进 lastIndex,下一次仍可能停在同一位置。
因此,只给正则加 g 不能修复。外层的 Promise.race 或 setTimeout 也无法抢占这次同步循环:事件循环被占用时,定时回调本身就没有机会执行。
换成符合文本约定的分隔条件
如果需求只是尽量在逗号处分段,可以采用明确的字符串 separator:
import _ from 'lodash';
const preview = _.truncate(text, {
length: 30,
separator: ',',
});
字符串分隔会改变截断边界,应先确认逗号是否应被保留、原来的省略号与长度规则是否符合界面要求。若业务只需要空白分词,可考虑确实消耗至少一个字符的已知模式,例如 /[ \t]+/;它不等价于“逗号之后允许零个空白”,不要不经需求核对就替换。
这里没有要求放弃全部正则,只是不能把可能空匹配的模式交给受影响循环。用 regex.test('') 检查一次也不充分:带前后文断言的正则可以只在非空字符串的某个位置产生空匹配。任意用户输入的正则还可能有其他复杂度问题,不能靠这项检查当成通用安全过滤器。
Lodash 4.18.1 的正式实现中,这个循环仍没有零长度匹配推进保护。自行把社区补丁复制进 node_modules 容易在重装后消失,也需要另行核对 Unicode、正则状态与边界处理,不宜当成稳定维护方案。
采用明确分隔方案后,在隔离环境用较短与较长文本、没有分隔符、分隔符恰好落在截断位置,以及含非 ASCII 字符的输入核对结果。需要对旧故障做回归时,应放在可由外部进程终止的独立工作进程中,设置真实进程级时限,不在共享服务线程中等待“它应该很快结束”。


