为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript:递归函数无法正确处理 Promise

JavaScript:递归函数无法正确处理 Promise

四季花海 2023-05-25 17:06:38
我正在用 Node.js 编写一个简单的游戏。玩家采取行动,这是作为承诺发出的。接下来检查移动的合法性:如果合法 - 很好,执行下一个“.then”如果不是 - 递归调用相同的函数以获得新的移动什么有效:我设法使用“reject”+“catch”打破承诺链并递归调用该函数。什么不起作用:当_makeMove第二次被调用时,它应该要求玩家采取新的行动,暂停直到他们回答。实际发生的是该函数只是运行到第 3 步,而不是等待玩家的进入。我正在通过终端输入,窗口仍然在“请输入:”,但代码已经跑掉了..(最终遇到“未定义”错误,这是很自然的,因为玩家还没有机会输入新的着法)。代码(简化):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      })  }我完全不解。为什么递归调用没有按预期工作?
查看完整描述

4 回答

?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

为了让您的承诺链从中获取价值_makeMove,您必须返回的结果_makeMove。不要担心价值是一个承诺;它将then在调用链中的下一个之前自动解析。


      .catch(err => {

        console.log('oops bad entry!')

        return _makeMove(activePlayer);

        //  ^ return here

      })

但是,_makeMove此处的结果将在 返回之前完成then,这可能会使您的recordMove调用返回两次。您可能需要拆分为_makeMove和_recordMove函数,以便递归调用_makeMove不会记录移动。


虽然理论上您可能会用完堆栈,但对于合理数量的移动尝试,它不会影响正确性。上面的两个错误会。


查看完整回答
反对 回复 2023-05-25
?
Qyouu

TA贡献1786条经验 获得超11个赞

我不确定你应该在这里使用递归调用。如果你得到一个非常垃圾的播放器,你可能会遇到 Stack Overflow 错误;)


const _makeMove = async (activePlayer) => {

  let proposedMove = null;


  while (1) {

    proposedMove = await activePlayer.proposeMove();

    if (gameBoard.checkLegal(proposedMove)) {

       break;

    }

  }

  activePlayer.recordMove(proposedMove);

  // do more stuff

}


查看完整回答
反对 回复 2023-05-25
?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

  1. .then使用async/await. 这解决了递归调用落到第 3 步而不是在第 2 步暂停的原始问题(我仍然觉得这很神奇......)

  2. 然而,这产生了一个新问题。最初我将一个链接.catch到函数的末尾async,但只触发了一次。即第 2、3、4 次递归调用会导致Unhandled exception错误。所以我改为将所有代码放在try函数内的一个块内,并将一个catch块也放在函数内。这很好用

查看完整回答
反对 回复 2023-05-25
?
MM们

TA贡献1886条经验 获得超2个赞

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);

    }

  };


查看完整回答
反对 回复 2023-05-25
  • 4 回答
  • 0 关注
  • 112 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信