我正在Node中编写一个简单的游戏。球员做出了一个动作,这是一个承诺。接下来,对此举的合法性进行检查:
- 如果合法-伟大,执行下一个"。那么">
- 如果不是-递归调用相同的函数以获得新的移动
什么是有效的:我设法使用";拒绝"+"捕获";并递归地调用该函数。
不起作用的是:当第二次调用_makeMove
时,它应该向玩家请求新的移动,暂停直到他们回复。实际发生的情况是,函数只运行到步骤3,不等待玩家的进入。
我正在通过终端接受输入,窗口仍然处于"0";请输入:";,但是代码已经跑了。。(最终打出了一个"未定义"的错误,这是很自然的,因为玩家还没有机会进入新的动作(。
代码(简化(:
const _makeMove = (activePlayer) => {
//player makes a move, which is returned as a promise
activePlayer.proposeMove()
//Step 1 - check if legal
.then(proposedMove => {
if (!gameBoard.checkLegal(proposedMove)) {
return Promise.reject("bad entry");
}
return proposedMove;
})
//Step 2 - record the move
.then(proposedMove => {
activePlayer.recordMove(proposedMove);
return proposedMove;
}) //unless step 1 fails...
.catch(err => {
console.log('oops bad entry!')
//in which case let's ask the player to move again...
//by calling the function RECURSIVELY
_makeMove(activePlayer);
})
//Step 3 - game goes on...
.then(proposedMove => {
//more stuff
})
}
我完全感到困惑。为什么递归调用没有按预期工作?
为了让您的承诺链从_makeMove
获取值,您必须返回_makeMove
的结果。不要担心承诺的价值;它将在调用链中的下一个CCD_ 4之前被自动解析。
.catch(err => {
console.log('oops bad entry!')
return _makeMove(activePlayer);
// ^ return here
})
但是,这里的_makeMove
结果将在返回then
之前完成,这可能会使您的recordMove
调用返回两次。您可能需要拆分为_makeMove
和_recordMove
函数,这样对_makeMove
的递归调用就不会记录移动。
尽管理论上可能会耗尽堆栈,但对于合理数量的移动尝试,它不会影响正确性。上面的两个错误会。
我不确定您是否应该在这里使用递归调用。如果你有一个非常转储的播放器,你可能会出现堆栈溢出错误;(
const _makeMove = async (activePlayer) => {
let proposedMove = null;
while (1) {
proposedMove = await activePlayer.proposeMove();
if (gameBoard.checkLegal(proposedMove)) {
break;
}
}
activePlayer.recordMove(proposedMove);
// do more stuff
}
感谢您的建议。经过修补,我最终做了两件事来解决它:
- 我使用
async/await
从一堆.then
方法重写了我的承诺链。这解决了递归调用进入第3步而不在第2步暂停的最初问题(我仍然觉得这很神奇。( - 然而,这就产生了一个新的问题。最初,我将一个
.catch
链接到async
函数的末尾,但这只触发了一次。即第二、第三、第四次递归调用将导致Unhandled exception
错误。因此,我将所有代码放在函数内的try
块内,并将catch
块也放在函数内。这个效果很好
最终代码:
const _makeMove = async (activePlayer) => {
try {
//Step 1 - take input
const proposedMove = await activePlayer.proposeMove();
//Step 2 - check if legal
if (!gameBoard.checkLegal(proposedMove)) {
throw new Error("bad entry");
}
//Step 3 - etc
//Step 4 - etc
//Step 5 - etc
} catch (e) {
console.log('oops bad entry!')
console.log("how it works: type 2 numbers ONLY, each between 1 and 3 (no spaces), to signify your move")
console.log("eg to place a mark into bottom left corner type 33. First cell = 11. Bang in the center = 22. You get it.")
console.log('lets try again...')
return _makeMove(activePlayer);
}
};