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

我正在用 Node.js 编写一个简单的游戏。玩家采取行动,这是作为承诺发出的。接下来检查移动的合法性:

  1. 如果合法 - 很好,执行下一个“.then”

  2. 如果不是 - 递归调用相同的函数以获得新的移动

什么有效:我设法使用“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

      })

  }

我完全不解。为什么递归调用没有按预期工作?


四季花海
浏览 149回答 4
4回答

ABOUTYOU

为了让您的承诺链从中获取价值_makeMove,您必须返回的结果_makeMove。不要担心价值是一个承诺;它将then在调用链中的下一个之前自动解析。      .catch(err => {        console.log('oops bad entry!')        return _makeMove(activePlayer);        //  ^ return here      })但是,_makeMove此处的结果将在 返回之前完成then,这可能会使您的recordMove调用返回两次。您可能需要拆分为_makeMove和_recordMove函数,以便递归调用_makeMove不会记录移动。虽然理论上您可能会用完堆栈,但对于合理数量的移动尝试,它不会影响正确性。上面的两个错误会。

Qyouu

我不确定你应该在这里使用递归调用。如果你得到一个非常垃圾的播放器,你可能会遇到 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}

收到一只叮咚

我.then使用async/await. 这解决了递归调用落到第 3 步而不是在第 2 步暂停的原始问题(我仍然觉得这很神奇......)然而,这产生了一个新问题。最初我将一个链接.catch到函数的末尾async,但只触发了一次。即第 2、3、4 次递归调用会导致Unhandled exception错误。所以我改为将所有代码放在try函数内的一个块内,并将一个catch块也放在函数内。这很好用

MM们

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);    }  };
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript