如何让<div>.innerHTML实时输出Connect Four AI对战中间状态?
四子棋AI对战页面实时输出中间状态问题
问题描述
我有一个基于Alpha-beta剪枝的四子棋AI对战页面,运行两个AI bot进行对战。目前遇到的问题是:尽管在对战过程中通过innerHTML向承载输出的<div>添加进度文本,但所有输出需等游戏结束后才会显示。如何实现将对战中间状态文本实时输出到目标<div>中?
问题代码
let text = ""; const output = document.getElementById('output-text-div'); const heuristicFunction = ...; const engine = ...; const depth = 8; let state = new ConnectFourBoard(); text += state.toString() + "<br/>"; function millis() { return new Date().valueOf(); } let totalDurationX = 0; let totalDurationO = 0; while (true) { text += "X's turn:<br/>"; let ta = millis(); state = engine.search(state, depth, X); let tb = millis(); totalDurationX += tb - ta; text += state.toString(); text += "<br/>"; text += "X AI duration: " + (tb - ta) + " milliseconds.<br/>"; output.innerHTML = text; if (state.isTie()) { text += "RESULT: It's a tie.<br/>"; break; } if (state.isWinningFor(X)) { text += "RESULT: X won.<br/>"; break; } text += "O's turn:<br/>"; output.innerHTML = text; var i = output.height; ta = millis(); state = engine.search(state, depth, O); tb = millis(); output.innerHTML = text; totalDurationO += tb - ta; text += state.toString(); text += "<br/>"; text += "O AI duration: " + (tb - ta) + " milliseconds.<br/>"; if (state.isTie()) { text += "RESULT: It's a tie.<br/>"; break; } if (state.isWinningFor(O)) { text += "RESULT: O won.<br/>"; break; } output.innerHTML = text; i = output.width; } text += "X AI total duration: " + totalDurationX + " milliseconds.<br/>"; text += "O AI total duration: " + totalDurationO + " milliseconds.<br/>"; output.innerHTML = text;
解决方案
问题根源
浏览器的UI渲染线程与JavaScript执行线程互斥,同步while(true)循环会持续阻塞JS线程,导致UI线程无法及时处理DOM更新请求,所有渲染操作会被延迟到循环结束后批量执行。
修复方法
将同步循环改为基于async/await的异步逻辑,每次AI思考完成后主动让出线程,给UI渲染留出时间:
修改后的代码
let text = ""; const output = document.getElementById('output-text-div'); const heuristicFunction = ...; const engine = ...; const depth = 8; let state = new ConnectFourBoard(); text += state.toString() + "<br/>"; output.innerHTML = text; function millis() { return new Date().valueOf(); } // 让出线程,允许UI渲染当前更新 async function yieldToUI() { await new Promise(resolve => setTimeout(resolve, 0)); } async function startBattle() { let totalDurationX = 0; let totalDurationO = 0; while (true) { text += "X's turn:<br/>"; output.innerHTML = text; await yieldToUI(); // 等待UI渲染当前文本 let ta = millis(); state = engine.search(state, depth, X); let tb = millis(); totalDurationX += tb - ta; text += state.toString(); text += "<br/>"; text += "X AI duration: " + (tb - ta) + " milliseconds.<br/>"; output.innerHTML = text; await yieldToUI(); if (state.isTie()) { text += "RESULT: It's a tie.<br/>"; break; } if (state.isWinningFor(X)) { text += "RESULT: X won.<br/>"; break; } text += "O's turn:<br/>"; output.innerHTML = text; await yieldToUI(); ta = millis(); state = engine.search(state, depth, O); tb = millis(); totalDurationO += tb - ta; text += state.toString(); text += "<br/>"; text += "O AI duration: " + (tb - ta) + " milliseconds.<br/>"; output.innerHTML = text; await yieldToUI(); if (state.isTie()) { text += "RESULT: It's a tie.<br/>"; break; } if (state.isWinningFor(O)) { text += "RESULT: O won.<br/>"; break; } } text += "X AI total duration: " + totalDurationX + " milliseconds.<br/>"; text += "O AI total duration: " + totalDurationO + " milliseconds.<br/>"; output.innerHTML = text; } // 启动对战 startBattle();
核心说明
yieldToUI函数通过setTimeout(resolve, 0)触发微任务,让JS线程暂时释放控制权,UI线程得以处理DOM更新并完成渲染- 每次修改
output.innerHTML后调用await yieldToUI(),确保中间状态能实时显示 - 整个对战逻辑封装在
async函数中,避免阻塞主线程
内容的提问来源于stack exchange,提问作者coderodde
相关产品推荐
相关产品推荐

