使用JS Fiddle实现了“ 5个猎人,3只兔子”的问题,在这里进行了描述:https://twitter.com/Mathgarden/status/1039247616616194048
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rabbit Hunters</title>
<link rel="stylesheet" href="htmltable.css">
<script language="JavaScript">
var size = 5;
var hunters = new Array();
var arena = new Array(side, side);
function hunter(row, col) {
this.row = row;
this.col = col;
}
function hunter(row, col) {
this.row = row;
this.col = col;
}
function resetArena() {
hunters = [];
redrawArena();
}
function generate_table() {
// get the reference for the body
var body = document.getElementsByTagName("body")[0];
// creates a <table> element and a <tbody> element
var tbl = document.createElement("table");
tbl.setAttribute("class", "huntertable");
var tblBody = document.createElement("tbody");
// creating all cells
for (var i = 0; i < size; i++) {
// creates a table row
var row = document.createElement("tr");
for (var j = 0; j < size; j++) {
// Create a <td> element and a text node, make the text
// node the contents of the <td>, and put the <td> at
// the end of the table row
var cell = document.createElement("td");
cell.addEventListener("click", cellClicked);
cell.bgColor = "green";
cell.innerHTML = "O";
row.appendChild(cell);
}
// add the row to the end of the table body
tblBody.appendChild(row);
}
// put the <tbody> in the <table>
tbl.appendChild(tblBody);
// appends <table> into <body>
body.appendChild(tbl);
// sets the border attribute of tbl to 2;
tbl.setAttribute("border", "5");
}
function cellClicked() {
var cellRow = this.parentNode.rowIndex;
var cellCol = this.cellIndex;
var cHunter = new hunter(cellRow, cellCol);
if (exists(cHunter)) {
// remove the hunter
remove(cHunter);
} else {
if (hunters.length == 5) {
alert("A maximum of 5 hunters are allowed!");
return;
}
hunters.push(cHunter);
redrawArena();
}
}
function exists(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col))
return true;
}
return false;
}
function remove(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col)) {
hunters.splice(i, 1);
break;
}
}
redrawArena();
}
function redrawArena() {
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
// reset arena
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
rCell.innerHTML = "O";
rCell.bgColor = "green";
}
}
for (var hunterIndex = 0; hunterIndex < hunters.length; hunterIndex++) {
// for each hunter mark the attacked territory:
hunterRow = hunters[hunterIndex].row;
hunterCol = hunters[hunterIndex].col;
huntRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
huntCell = huntRow.getElementsByTagName("td")[hunterCol];
huntCell.innerHTML = "H";
huntCell.bgColor = "red";
// horizontal and vertical
for (var i = 0; i < size; i++) {
hRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
hCell = hRow.getElementsByTagName("td")[i];
hCell.bgColor = "red";
vRow = arenaTBody.getElementsByTagName("tr")[i];
vCell = vRow.getElementsByTagName("td")[hunterCol];
vCell.bgColor = "red";
}
// diagonals
for (var i = 1; i < size; i++) {
if (((hunterRow + i) < size) && ((hunterCol + i) < size)) {
dRow1 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell1 = dRow1.getElementsByTagName("td")[hunterCol + i];
dCell1.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol - i) >= 0)) {
dRow2 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell2 = dRow2.getElementsByTagName("td")[hunterCol - i];
dCell2.bgColor = "red";
}
if (((hunterRow + i) < size) && ((hunterCol - i) >= 0)) {
dRow3 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell3 = dRow3.getElementsByTagName("td")[hunterCol - i];
dCell3.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol + i) < size)) {
dRow4 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell4 = dRow4.getElementsByTagName("td")[hunterCol + i];
dCell4.bgColor = "red";
}
}
}
alert("Checking for win ...");
checkWin();
}
function checkWin() {
// check arena for 5 hunters and 3 rabbits...
if (hunters.length < 5)
return;
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
var rabbits = 0;
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
if (rCell.bgColor == "green") {
rabbits++;
}
}
}
if (rabbits == 3)
alert("Congrats! You did it!")
}
</script>
</head>
<body onload="generate_table()">
<h1>Rabbit Hunters</h1>
<p>
<ol>
<li>The grid below represents a forest filled with rabbits (green).</li>
<li>Hunters can attack horizontally and diagonally in all directions (like a chess queen).</li>
<li>Once placed, hunters will kill all rabbits in their lines of sight (try clicking!).</li>
<li>To remove hunters just click on them again.</li>
<li>The Reset button clears the whole forest.</li>
</ol>
<strong>Can you place 5 hunters on the grid below so that they spare 3 rabbits (three green squares should remain)?</strong>
</p>
<p>
<input type="button" value="Reset" onclick="resetArena()" />
</p>
</body>
</html>
=====================
我的问题是:为什么在绘制最后一个猎人之前(或竞技场被完全重画之前)显示“正在检查获胜...”警报。我添加了此调试警报,因为即使我将checkWin()函数称为之后,重绘循环也已完全完成,它似乎想首先开始执行checkWin()。因此,只有在警报发出后,最后一次单击的猎人方格才变成“ H”,而我希望它在检查获胜之前就变成了。
谢谢!
答案 0 :(得分:1)
在功能checkWin
中的任何其他代码之前,并未真正调用您的功能redrawArena
。所描述的问题是由于代码的使用引起的,该代码阻塞了浏览器的主UI线程,该线程用于更新渲染的文档并执行其JS代码(工人除外)。因此,如果您动态更改文档中某些元素的属性(如CSS样式),浏览器可能不会立即重新绘制(或重排)文档,通常会在调用堆栈中已经存在的所有JS函数弹出后(即返回)值)。让我们将函数代码的某些部分称为“阻止代码”,如果它可以防止该函数长时间返回其值(足够长的时间以使网站对用户无响应的话)。阻塞代码的最常见来源是同步XMLHttpRequest,本地JS对话框,长时间运行的循环(例如,一些繁重的计算)等。
这是一个简单的示例,展示了更长的运行循环(第一次更改颜色后)将如何阻止文档的重新绘制,因此您将永远不会看到“忙碌状态”(红色):
#status {
display: inline-block;
width: 10px;
height: 10px;
background-color: gray;
}
<!DOCTYPE html>
<html>
<head>
<script>
function start(){
setStatus('red');
compute();
}
function compute(){
var a = [];
for (var i = 0; i < 10; i+=0.000001){
a.push(Math.sin(i) + Math.cos(i));
}
setStatus('green');
}
function setStatus(color){
document.getElementById('status').style.backgroundColor = color;
}
</script>
</head>
<body>
<div>Status: <div id="status"></div></div>
<button onclick="start()">Compute</button>
<button onclick="setStatus(null)">Reset</button>
</body>
</html>
很显然,代码中的这种线程阻塞行为只能由alert()
调用引起。但是,这里出现一个问题-您使用哪个浏览器测试代码?根据{{3}}:
- 向用户显示消息。
- (可选)在等待用户确认消息时暂停。
然后是alert spec:
- 如有必要,更新任何文档或浏览上下文的呈现或用户界面以反映当前状态。
- 等待直到达到条件目标。当用户代理具有暂停的任务时,相应的事件循环不得运行其他任务,并且当前正在运行的任务中的任何脚本都必须阻止。用户代理在暂停时应保持对用户输入的响应,尽管容量会降低,因为事件循环不会做任何事情。
警报不应阻止呈现(UI可能会在暂停期间刷新),并且从理论上讲,它在等待用户时不需要阻止任何后续的JS代码(因为规范说暂停是可选的)。
但是,浏览器并不总是遵循规范(在暂停的情况下,允许并鼓励进行实验),因此我决定在当前计算机(Win7)上可用的几种浏览器上测试您的代码:
|-------------|---------------------|-----------------------|
| | | |
| browser | blocks UI refresh | executes subsequent |
| | during alert | code during alert |
| | | |
|-------------|---------------------|-----------------------|
| Chrome 69.0 | yes | no* |
|-------------|---------------------|-----------------------|
| Opera 55.0 | yes | no |
|-------------|---------------------|-----------------------|
| FF Dev 63.0 | no | no |
|-------------|---------------------|-----------------------|
| FF 62.0 | no | no |
|-------------|---------------------|-----------------------|
| FF 60.2 | no | no |
|-------------|---------------------|-----------------------|
| FF 52.9 | no | no |
|-------------|---------------------|-----------------------|
| IE 11 | no | no |
|-------------|---------------------|-----------------------|
从上表中可以看到,我仅在Chrome和Opera(相同的渲染引擎,当前最新的稳定版本)中遇到了描述的问题。在警报期间,没有经过测试的浏览器将不会运行任何后续的JS代码,但是,如果在显示第一个警报(*
之前触发了这些事件,则Chrome似乎会将输入事件的回调推入调用堆栈。例如。如果您一次又一次地单击表格单元格,则函数cellClicked
将被调用多次(因此,如果您确认第一个警报,Chrome将更新UI状态并显示另一个警报)。表中的任何其他浏览器似乎都没有这种行为。
要避免潜在的不必要的未决UI更新阻塞,最直接的解决方案是在执行阻塞代码之前,让浏览器有时间执行更新。这可以通过将警报和后续代码移入异步回调(例如,通过使用setTimeout
函数。在以下代码段中,我将函数checkWin()
中的警报“ Checking for win ...”和redrawArena
的调用移到了其中添加的setTimeout
函数的回调中。这将允许浏览器在显示任何警报之前刷新您的表,从而绕过受影响的浏览器中有害的UI阻止效果。您还可以使用setTimeout的 delay 参数来查找最小值,该最小值将允许在所有目标浏览器中触发UI刷新。
.huntertable tr {
cursor: pointer;
}
.huntertable td {
font-size: 40px;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rabbit Hunters</title>
<script>
var size = 5;
var hunters = new Array();
function hunter(row, col) {
this.row = row;
this.col = col;
}
function resetArena() {
hunters = [];
redrawArena();
}
function generate_table() {
// get the reference for the body
var body = document.getElementsByTagName("body")[0];
// creates a <table> element and a <tbody> element
var tbl = document.createElement("table");
tbl.setAttribute("class", "huntertable");
var tblBody = document.createElement("tbody");
// creating all cells
for (var i = 0; i < size; i++) {
// creates a table row
var row = document.createElement("tr");
for (var j = 0; j < size; j++) {
// Create a <td> element and a text node, make the text
// node the contents of the <td>, and put the <td> at
// the end of the table row
var cell = document.createElement("td");
cell.addEventListener("click", cellClicked);
cell.bgColor = "green";
cell.innerHTML = "O";
row.appendChild(cell);
}
// add the row to the end of the table body
tblBody.appendChild(row);
}
// put the <tbody> in the <table>
tbl.appendChild(tblBody);
// appends <table> into <body>
body.appendChild(tbl);
// sets the border attribute of tbl to 2;
tbl.setAttribute("border", "5");
}
function cellClicked() {
var cellRow = this.parentNode.rowIndex;
var cellCol = this.cellIndex;
var cHunter = new hunter(cellRow, cellCol);
if (exists(cHunter)) {
// remove the hunter
remove(cHunter);
} else {
if (hunters.length == 5) {
alert("A maximum of 5 hunters are allowed!");
return;
}
hunters.push(cHunter);
redrawArena();
}
}
function exists(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col))
return true;
}
return false;
}
function remove(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col)) {
hunters.splice(i, 1);
break;
}
}
redrawArena();
}
function redrawArena() {
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
// reset arena
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
rCell.innerHTML = "O";
rCell.bgColor = "green";
}
}
for (var hunterIndex = 0; hunterIndex < hunters.length; hunterIndex++) {
// for each hunter mark the attacked territory:
hunterRow = hunters[hunterIndex].row;
hunterCol = hunters[hunterIndex].col;
huntRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
huntCell = huntRow.getElementsByTagName("td")[hunterCol];
huntCell.innerHTML = "H";
huntCell.bgColor = "red";
// horizontal and vertical
for (var i = 0; i < size; i++) {
hRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
hCell = hRow.getElementsByTagName("td")[i];
hCell.bgColor = "red";
vRow = arenaTBody.getElementsByTagName("tr")[i];
vCell = vRow.getElementsByTagName("td")[hunterCol];
vCell.bgColor = "red";
}
// diagonals
for (var i = 1; i < size; i++) {
if (((hunterRow + i) < size) && ((hunterCol + i) < size)) {
dRow1 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell1 = dRow1.getElementsByTagName("td")[hunterCol + i];
dCell1.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol - i) >= 0)) {
dRow2 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell2 = dRow2.getElementsByTagName("td")[hunterCol - i];
dCell2.bgColor = "red";
}
if (((hunterRow + i) < size) && ((hunterCol - i) >= 0)) {
dRow3 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell3 = dRow3.getElementsByTagName("td")[hunterCol - i];
dCell3.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol + i) < size)) {
dRow4 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell4 = dRow4.getElementsByTagName("td")[hunterCol + i];
dCell4.bgColor = "red";
}
}
}
setTimeout(function() {
alert("Checking for win ...");
checkWin();
},20);
}
function checkWin() {
// check arena for 5 hunters and 3 rabbits...
if (hunters.length < 5)
return;
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
var rabbits = 0;
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
if (rCell.bgColor == "green") {
rabbits++;
}
}
}
if (rabbits == 3)
alert("Congrats! You did it!")
}
</script>
</head>
<body onload="generate_table()">
<h1>Rabbit Hunters</h1>
<p>
<ol>
<li>The grid below represents a forest filled with rabbits (green).</li>
<li>Hunters can attack horizontally and diagonally in all directions (like a chess queen).</li>
<li>Once placed, hunters will kill all rabbits in their lines of sight (try clicking!).</li>
<li>To remove hunters just click on them again.</li>
<li>The Reset button clears the whole forest.</li>
</ol>
<strong>Can you place 5 hunters on the grid below so that they spare 3 rabbits (three green squares should remain)?</strong>
</p>
<p>
<input type="button" value="Reset" onclick="resetArena()" />
</p>
</body>
</html>
但是,在大多数情况下(如您的情况),最好将这种输出直接显示在文档中。这样,您的消息将在下次UI刷新时与DOM中的其他更改一起显示。借助HTML,CSS和JS,您可以创建用于显示消息的个人方法(包括自定义模式,信息栏等)。在下面的代码段中,我创建了一个非常简单的示例,您的应用如何将消息输出给用户。基本上,我添加了用于显示消息的附加div,创建了两个用于在此div中显示/删除消息的功能(showMessage
/ removeMessage
),并用showMessage调用替换了警报(并删除了无意义的警报“检查胜利” ...”)。
.huntertable tr {
cursor: pointer;
}
.huntertable td {
font-size: 40px;
text-align: center;
}
#infobar {
color: red;
font-weight: bold;
margin-bottom: 10px;
visibility: hidden;
min-height: 20px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rabbit Hunters</title>
<script>
var size = 5;
var hunters = new Array();
function hunter(row, col) {
this.row = row;
this.col = col;
}
function showMessage(msgText) {
var infobar = document.getElementById('infobar');
infobar.innerHTML = msgText;
infobar.style.visibility = 'visible';
}
function removeMessage() {
var infobar = document.getElementById('infobar');
infobar.innerHTML = '';
infobar.style.visibility = null;
}
function resetArena() {
removeMessage();
hunters = [];
redrawArena();
}
function generate_table() {
// get the reference for the body
var body = document.getElementsByTagName("body")[0];
// creates a <table> element and a <tbody> element
var tbl = document.createElement("table");
tbl.setAttribute("class", "huntertable");
var tblBody = document.createElement("tbody");
// creating all cells
for (var i = 0; i < size; i++) {
// creates a table row
var row = document.createElement("tr");
for (var j = 0; j < size; j++) {
// Create a <td> element and a text node, make the text
// node the contents of the <td>, and put the <td> at
// the end of the table row
var cell = document.createElement("td");
cell.addEventListener("click", cellClicked);
cell.bgColor = "green";
cell.innerHTML = "O";
row.appendChild(cell);
}
// add the row to the end of the table body
tblBody.appendChild(row);
}
// put the <tbody> in the <table>
tbl.appendChild(tblBody);
// appends <table> into <body>
body.appendChild(tbl);
// sets the border attribute of tbl to 2;
tbl.setAttribute("border", "5");
}
function cellClicked() {
removeMessage();
var cellRow = this.parentNode.rowIndex;
var cellCol = this.cellIndex;
var cHunter = new hunter(cellRow, cellCol);
if (exists(cHunter)) {
// remove the hunter
remove(cHunter);
} else {
if (hunters.length == 5) {
showMessage("A maximum of 5 hunters are allowed!");
return;
}
hunters.push(cHunter);
redrawArena();
}
}
function exists(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col))
return true;
}
return false;
}
function remove(hunter) {
for (var i = 0; i < hunters.length; i++) {
if ((hunters[i].row == hunter.row) && (hunters[i].col == hunter.col)) {
hunters.splice(i, 1);
break;
}
}
redrawArena();
}
function redrawArena() {
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
// reset arena
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
rCell.innerHTML = "O";
rCell.bgColor = "green";
}
}
for (var hunterIndex = 0; hunterIndex < hunters.length; hunterIndex++) {
// for each hunter mark the attacked territory:
hunterRow = hunters[hunterIndex].row;
hunterCol = hunters[hunterIndex].col;
huntRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
huntCell = huntRow.getElementsByTagName("td")[hunterCol];
huntCell.innerHTML = "H";
huntCell.bgColor = "red";
// horizontal and vertical
for (var i = 0; i < size; i++) {
hRow = arenaTBody.getElementsByTagName("tr")[hunterRow];
hCell = hRow.getElementsByTagName("td")[i];
hCell.bgColor = "red";
vRow = arenaTBody.getElementsByTagName("tr")[i];
vCell = vRow.getElementsByTagName("td")[hunterCol];
vCell.bgColor = "red";
}
// diagonals
for (var i = 1; i < size; i++) {
if (((hunterRow + i) < size) && ((hunterCol + i) < size)) {
dRow1 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell1 = dRow1.getElementsByTagName("td")[hunterCol + i];
dCell1.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol - i) >= 0)) {
dRow2 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell2 = dRow2.getElementsByTagName("td")[hunterCol - i];
dCell2.bgColor = "red";
}
if (((hunterRow + i) < size) && ((hunterCol - i) >= 0)) {
dRow3 = arenaTBody.getElementsByTagName("tr")[hunterRow + i];
dCell3 = dRow3.getElementsByTagName("td")[hunterCol - i];
dCell3.bgColor = "red";
}
if (((hunterRow - i) >= 0) && ((hunterCol + i) < size)) {
dRow4 = arenaTBody.getElementsByTagName("tr")[hunterRow - i];
dCell4 = dRow4.getElementsByTagName("td")[hunterCol + i];
dCell4.bgColor = "red";
}
}
}
checkWin();
}
function checkWin() {
// check arena for 5 hunters and 3 rabbits...
if (hunters.length < 5)
return;
var arenaTable = document.getElementsByTagName("tbl")[0];
var arenaTBody = document.getElementsByTagName("tbody")[0];
var rabbits = 0;
for (var rowi = 0; rowi < size; rowi++) {
for (var coli = 0; coli < size; coli++) {
rRow = arenaTBody.getElementsByTagName("tr")[rowi];
rCell = rRow.getElementsByTagName("td")[coli];
if (rCell.bgColor == "green") {
rabbits++;
}
}
}
if (rabbits == 3)
showMessage("Congrats! You did it!");
}
</script>
</head>
<body onload="generate_table()">
<h1>Rabbit Hunters</h1>
<p>
<ol>
<li>The grid below represents a forest filled with rabbits (green).</li>
<li>Hunters can attack horizontally and diagonally in all directions (like a chess queen).</li>
<li>Once placed, hunters will kill all rabbits in their lines of sight (try clicking!).</li>
<li>To remove hunters just click on them again.</li>
<li>The Reset button clears the whole forest.</li>
</ol>
<strong>Can you place 5 hunters on the grid below so that they spare 3 rabbits (three green squares should remain)?</strong>
</p>
<p>
<input type="button" value="Reset" onclick="resetArena()" />
</p>
<div id="infobar"></div>
</body>
</html>
通常,您应该避免使用JS警报来显示应用程序的常规文本输出或对其进行调试。警报可能会阻止某些浏览器中的UI刷新,直到用户确认它们为止,并且它们可能会被浏览器阻止,从而使它们不可靠地显示重要信息。如果需要向用户显示消息,则应创建一种或多种方法在文档中动态显示消息(实际上可以在Web上找到许多不同的解决方案)。为了进行调试,您应该使用集成在每个现代浏览器中的“开发工具”面板以及pause spec对象中的方法。如果您仍然坚持在应用程序中使用警报,并且由于警报而遇到不必要的页面UI刷新阻塞或不相关的代码,则可能需要将其放入异步回调中。