首页 > 解决方案 > 如果你让一个函数异步并且什么都不改变会发生什么?

问题描述

我有一个数独板实现为 HTML 表和一个按钮,单击该按钮时使用 javascript 中的递归回溯算法解决数独板。现在我想这样做,以便您可以通过在我的递归函数中不立即更改 HTML 来查看所做的调整。我尝试使函数异步,然后调用此函数

function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

像这样

for (let choice = 1; choice <= 9; choice++) {
      this.boardArray[row][col] = choice;
      // put delay here
      await sleep(250);
      currEntry.textContent = choice;
      if (this.choiceOkay(row, col)) {
        const solved = this.solveBoard(nextRow, nextCol);
        if (solved) {
          return true;
        }
      }

这确实给了我最初想要的行为,但仅限于董事会的一部分,然后它似乎就停止了。我删除了对 sleep 函数的调用,并尝试了它,唯一的改变是函数声明前面的“异步”,它仍然只做了板的一部分,但这次一次全部完成,没有视觉延迟。我想知道为什么让这个函数异步会导致这个逻辑错误?

提前致谢!

此外,这是我关于 Stack Overflow 的第一个问题,所以如果我需要更具体或类似的任何内容,请告诉我。

标签: javascriptrecursionasync-await

解决方案


函数前面的async关键字基本上是说:

这个函数将返回一个 Promise

您的sleep函数已经返回 a Promise,因此编写关键字async是无用的。

重要的是await关键字,它基本上说:

在我的右边,可能有一个异步函数(同上一个 Promise)。等我回来再继续

如果你写了async function sleep,但在调用时省略await关键字sleep,你会在本质上抛出函数调用并且永远不会等待它的返回(因此你的代码“无延迟”运行)

如果你想要延迟,最好让你的算法保持原样,让你的算法的调用者告诉你的算法继续与否。您可以为此使用generators。(另一种可能是蹦床)。

function* runAlgo () {
  for (let choice = 1; choice <= 9; choice++) {
    yield; // gives control back to delayer
    console.log('choice : ', choice)
    // do your algo and put some yield wherever you like
  }
}
// no need for async, a Promise is already returned
function sleep (t) {
  return new Promise((ok, ko) => setTimeout(ok, t))
}
async function delayer () { // need for async so we can use the await keyword below
  const it = runAlgo()
  let next = it.next()
  while (!next.done) {
    await sleep(1000)
    next = it.next()
  }
}
delayer()


然而,解决你的板很可能会冻结你的用户界面。所以你也想在solvingBoard里面等待:

function* solveBoard () {
  let i = 0
  while (i < 5) { //freezes the ui if not yielding
    yield i++
  }
}
function* runAlgo () {
  for (let choice = 1; choice <= 9; choice++) {
    yield 'choice : '+choice; // gives control back to caller
    yield* solveBoard()
  }
}
// no need for async, a Promise is already returned
function sleep (t) {
  return new Promise((ok, ko) => setTimeout(ok, t))
}
async function delayer () { // need for async so we can use the await keyword below
  const it = runAlgo()
  let next = it.next()
  while (!next.done) {
    await sleep(1000)
    next = it.next()
    console.log('data', next.value)
  }
}
delayer()


推荐阅读