You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS生成9长度随机倍率数组时触发无限循环的问题排查

生成随机奖券数组时触发无限循环问题修复

问题说明

需求逻辑:

  • 从倍率池["x10", "x20", "x30", "x40", "x50", "x60"]中随机选出3个不重复的倍率值
  • 最终生成长度为9的数组,选中的3个倍率每个恰好出现3次,位置随机排布
  • 实际运行编写的代码时进入无限循环,无法输出预期结果

无限循环触发原因

核心bug为第二个填充数组的for循环终止条件写错:

  • 需要的数组总长度为9,但循环终止条件写的是i < 10,逻辑上会尝试完成10次有效元素插入
  • 当数组已经填充到9个元素(3个倍率各3个)时,i会自增到9,满足i < 10的循环进入条件,此时无论随机到哪个倍率,push后该倍率的计数都会达到4,触发pop() + i--的回退逻辑:
    • pop移除刚加入的元素,数组长度回到9
    • i被减为8,本轮循环结束后i自增重回9
    • 循环判断条件永远成立,代码卡在该步骤无限重复执行
      除此之外,原有的随机插入逻辑即使修改了循环终止条件,也存在性能不稳定的问题:当数组只剩最后1个空位、且仅对应1个未满额的倍率时,随机选值有2/3概率选到已满额的倍率,会反复触发回退逻辑,极端情况下会卡顿很久才能完成填充。

优化实现方案

更稳妥的实现思路是先生成符合数量要求的元素集合,再通过Fisher-Yates洗牌算法打乱顺序,完全避免循环回退、卡住的问题:

const victoryMultipliers = ["x10", "x20", "x30", "x40", "x50", "x60"];

// 随机选3个不重复的倍率
const threeTicketArray = [];
while (threeTicketArray.length < 3) {
  const randVal = victoryMultipliers[Math.floor(Math.random() * victoryMultipliers.length)];
  if (!threeTicketArray.includes(randVal)) {
    threeTicketArray.push(randVal);
  }
}

// 生成每个倍率恰好出现3次的基础数组
const ticketArray = threeTicketArray.flatMap(multiplier => Array(3).fill(multiplier));

// 洗牌算法随机打乱数组顺序
for (let i = ticketArray.length - 1; i > 0; i--) {
  const randomIndex = Math.floor(Math.random() * (i + 1));
  [ticketArray[i], ticketArray[randomIndex]] = [ticketArray[randomIndex], ticketArray[i]];
}

console.log(ticketArray);

如果要沿用原本的循环插入逻辑,仅需要把第二个for循环的终止条件从i < 10修改为i < 9即可解决无限循环问题,但不推荐这种写法,稳定性较差。

内容的提问来源于stack exchange,提问作者Mohamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:57:17