JS编写质数检测函数时DOM实时更新失效问题求助
问题根因
- 浏览器的渲染主线程是单线程的,同步执行的计算任务会抢占线程资源,导致DOM更新、页面重绘任务被挂起,只有当所有同步JS代码执行完毕后,浏览器才会统一渲染DOM的变更,因此你看不到processing状态,也看不到质数数量的实时更新。
- 原代码存在逻辑缺陷:
for (let i = 0;i<value;i++)循环开头每次都执行time.textContent = ''、amount.textContent = '',会清空之前的计数,就算线程不阻塞也无法实现数值累加。
修复方案1:分批计算(无额外API,兼容性好)
将长循环拆分成多个小批次执行,每执行完一批就把控制权交还给浏览器更新DOM,再执行下一批,代码修改如下:
JS代码
let time = document.getElementById('time') let texts = document.getElementById('texts') let amount = document.getElementById('amount') let status = document.getElementById('status') async function checkprimenumber(){ let start = performance.now() let value = texts.value || texts.placeholder value = Number(value) // 先更新状态,给浏览器留渲染时间 status.textContent = 'processing' amount.textContent = '0' time.textContent = '' // 等待16ms让浏览器完成DOM渲染 await new Promise(resolve => setTimeout(resolve, 16)) let primeCount = 0 // 每批次计算100个数字,可根据性能调整 const BATCH_SIZE = 100 for (let batchStart = 0; batchStart < value; batchStart += BATCH_SIZE) { let batchEnd = Math.min(batchStart + BATCH_SIZE, value) for (let i = batchStart; i < batchEnd; i++) { let nums = 2 for (let x = 2; x <= Math.sqrt(i); x++) { // 优化质数判断逻辑,只需要判断到平方根即可 if (i % x === 0) { nums++ break } } if (nums === 2 && i >=2) { // 质数判断条件修正 primeCount++ } } // 每批次计算完更新DOM amount.textContent = primeCount // 交控制权给浏览器渲染 await new Promise(resolve => requestAnimationFrame(resolve)) } // 全部计算完毕更新状态 status.textContent = 'done' let end = performance.now() time.textContent = (end-start).toFixed(3) }
HTML代码不用修改,保留原有结构即可。
修复方案2:Web Worker(更适合大数值计算,不卡页面)
如果需要计算的数值范围很大,推荐用Web Worker把计算逻辑放到后台线程执行,完全不阻塞主线程的DOM更新:
- 新建一个
prime.worker.js文件,放计算逻辑:
// prime.worker.js self.onmessage = (e) => { const max = e.data let count = 0 for (let i = 2; i <= max; i++) { let isPrime = true for (let x = 2; x <= Math.sqrt(i); x++) { if (i % x === 0) { isPrime = false break } } if (isPrime) { count++ // 实时发送计数到主线程 self.postMessage({ type: 'count', value: count }) } } // 计算完成发送结束信号 self.postMessage({ type: 'done' }) }
- 主线程JS修改为:
let time = document.getElementById('time') let texts = document.getElementById('texts') let amount = document.getElementById('amount') let status = document.getElementById('status') let primeWorker = new Worker('./prime.worker.js') function checkprimenumber(){ let start = performance.now() let value = texts.value || texts.placeholder value = Number(value) status.textContent = 'processing' amount.textContent = '0' time.textContent = '' primeWorker.onmessage = (e) => { if (e.data.type === 'count') { amount.textContent = e.data.value } else if (e.data.type === 'done') { status.textContent = 'done' let end = performance.now() time.textContent = (end - start).toFixed(3) } } primeWorker.postMessage(value) }
内容的提问来源于stack exchange,提问作者Shawn
相关产品推荐
相关产品推荐

