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

如何在React中为轮盘赌模拟函数添加可实时更新的进度条

核心问题说明

你当前的模拟函数为同步执行,JavaScript单线程运行特性会导致大计算量执行期间,浏览器主线程被完全占用,无法响应任何UI渲染操作,因此进度条无法实时更新。

实现方案

我们将同步模拟逻辑改造为异步分批次执行,每完成1%的计算量就更新一次进度,同时让出主线程给浏览器渲染UI,既保证进度实时同步,也不会阻塞用户交互。

第一步:改造模拟函数

改造原同步函数为异步版本,支持传入进度回调,同时优化内存占用(无需存储全量模拟结果):

// 改造后的异步轮盘赌模拟函数
const SimulateEuroRouletteAsync = async (
  starting_balance, 
  wagering, 
  bet_size, 
  simulations,
  onProgress // 进度回调,入参为0-100的整数进度值
) => {
  let bust_out_count = 0
  let balance_total = 0
  let wagering_total = 0
  // 按1%比例拆分计算批次
  const batchSize = Math.max(1, Math.floor(simulations / 100))
  let processed = 0

  for(let batch = 0; batch < 100; batch++){
    // 执行当前批次模拟
    const batchEnd = Math.min(processed + batchSize, simulations)
    for(let i = processed; i < batchEnd; i++){
      let balance = starting_balance
      let wagering_complete = 0
      let bust_out = false
      
      while(bet_size <= balance && wagering_complete < wagering){
        // 保留原有随机数生成逻辑,注意random.int需要为你项目中已实现的方法
        const random_int = random.int(0, 36)
        balance -= bet_size
        if(random_int > 18){
          balance += bet_size * 2
        }
        wagering_complete += bet_size
      }

      bust_out = balance < bet_size && wagering > wagering_complete
      if(bust_out) bust_out_count++
      else balance_total += balance
      wagering_total += wagering_complete
      processed++
    }
    // 更新进度
    onProgress?.(Math.min(Math.round((processed / simulations) * 100), 100))
    // 让出主线程给浏览器渲染UI
    await new Promise(resolve => setTimeout(resolve, 0))
    if(processed >= simulations) break
  }

  return { 
    ev: balance_total / simulations, 
    average_wagered: wagering_total / simulations, 
    bust_out_rate: ((bust_out_count / simulations) * 100), 
    simulated: processed 
  }
}

第二步:React组件接入进度条

在组件中维护进度状态,调用异步模拟函数实现进度同步更新:

import { useState } from 'react'

const RouletteSimulator = () => {
  // 模拟参数可替换为你的表单输入值
  const [params] = useState({
    starting_balance: 1000,
    wagering: 5000,
    bet_size: 10,
    simulations: 1000000
  })
  const [progress, setProgress] = useState(0)
  const [result, setResult] = useState(null)
  const [isRunning, setIsRunning] = useState(false)

  const startSimulate = async () => {
    setIsRunning(true)
    setProgress(0)
    setResult(null)
    const simResult = await SimulateEuroRouletteAsync(
      params.starting_balance,
      params.wagering,
      params.bet_size,
      params.simulations,
      setProgress
    )
    setResult(simResult)
    setIsRunning(false)
  }

  return (
    <div style={{padding: '20px'}}>
      <button onClick={startSimulate} disabled={isRunning}>
        {isRunning ? '模拟运行中' : '开始模拟'}
      </button>

      {/* 进度条UI */}
      {isRunning && (
        <div style={{margin: '16px 0', height: '24px', background: '#eee', borderRadius: '12px', overflow: 'hidden'}}>
          <div 
            style={{height: '100%', width: `${progress}%`, background: '#1677ff', transition: 'width 0.1s linear'}}
          />
          <span style={{position: 'relative', top: '-22px', left: '50%', transform: 'translateX(-50%)'}}>
            {progress}%
          </span>
        </div>
      )}

      {/* 结果展示 */}
      {result && (
        <div style={{marginTop: '20px'}}>
          <p>预期回报:{result.ev.toFixed(2)}</p>
          <p>平均投注额:{result.average_wagered.toFixed(2)}</p>
          <p>破产率:{result.bust_out_rate.toFixed(2)}%</p>
        </div>
      )}
    </div>
  )
}

export default RouletteSimulator
可选优化
  • 若觉得100次进度更新太频繁,可调整批次拆分比例,比如每5%更新一次,减少重渲染开销
  • 模拟量超过1000万次时,可使用Web Worker在后台线程执行计算,完全不占用主线程资源
  • 可将setTimeout替换为requestIdleCallback,利用浏览器空闲时间执行计算,进一步降低对交互的影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 12:36:04