为什么回调地狱起作用而 async/await 不起作用? (在我正在测试的这种特殊情况下)

Why does the callback hell works and the async/await doesnt? (in this particular case that i am testing)

我有这两个代码(一个我使用回调地狱,另一个 async/await):

function sleep(seconds) {
  const date = Date.now();
  milliseconds = seconds * 1000;
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

const callBackHell = () => {
  return Promise.resolve().then((v) => {
    sleep(1);
    console.log("ameno");
    return Promise.resolve().then((v) => {
      sleep(1);
      console.log("dorime");
      return Promise.resolve().then((v) => {
        sleep(1);
        return console.log("latireno");
      });
    });
  });
};

console.log(1);

callBackHell();

console.log(2);

console.log(3);

回调地狱如我想象的那样工作(字符串日志最后出现)。

然后我尝试转换相同的代码,但使用 async/await,像这样:

function sleep(seconds) {
  const date = Date.now();
  milliseconds = seconds * 1000;
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

const consoleMusical = async (letra) => {
  sleep(1);
  console.log(letra);
};

async function codeBlockerAwait() {
  await consoleMusical("ameno");
  await consoleMusical("dorime");
  await consoleMusical("latiereno");
}

console.log(1);
codeBlockerAwait();
console.log(2);
console.log(3);

现在第一个 await 阻塞了主线程,而另外两个则一直显示在 last。我做错了什么?

使用@Muhammad Saquib Shaikh 解决方案编辑:

function sleep(seconds) {
  const date = Date.now();
  milliseconds = seconds * 1000;
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

const consoleMusical = async (letra) => {
  sleep(1);
  console.log(letra);
};

async function codeBlockerAwait() {
  await consoleMusical("ameno");
  await consoleMusical("dorime");
  await consoleMusical("latiereno");
}

(async function () {
  console.log(1);
  await codeBlockerAwait();
  console.log(2);
  console.log(3);
})();

它与第一个输出不同。

Now the first await blocks the main thread while the other two keeps showing lastly. What am i doing wrong?

ameno 被预先记录的原因是您在 任何 await 之前有该日志语句 。要评估行 await consoleMusical("ameno");,它必须执行 consoleMusical('ameno'),获取其 return 值,然后才能 await.

另一个 console.logs 发生在 await 之后,因此它们将作为微任务排队到 运行 在当前正在执行的代码的其余部分之后。

相比之下,callBackHell 的所有 console.logs 都在第一个 promise 中。所以它们都将作为微任务排队。


如果您使用异步睡眠而不是同步睡眠,这个问题就会消失。作为奖励,您不会锁定浏览器:

function sleep(seconds) {
  return new Promise(resolve => {
    setTimeout(resolve, seconds * 1000);
  });
}

const consoleMusical = async (letra) => {
  await sleep(1);
  console.log(letra);
};

async function codeBlockerAwait() {
  await consoleMusical("ameno");
  await consoleMusical("dorime");
  await consoleMusical("latiereno");
}

console.log(1);
codeBlockerAwait();
console.log(2);
console.log(3);

如果您绝对必须进行同步睡眠,同时仍希望保持相同的操作顺序,则需要添加一个额外的等待。

function sleep(seconds) {
  const date = Date.now();
  milliseconds = seconds * 1000;
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

const consoleMusical = async (letra) => {
  sleep(1);
  console.log(letra);
};

async function codeBlockerAwait() {
  await undefined; // <--------- added
  await consoleMusical("ameno");
  await consoleMusical("dorime");
  await consoleMusical("latiereno");
}


console.log(1);
codeBlockerAwait();
console.log(2);
console.log(3);

.then代码保证异步执行。因此,callBackHell returns 立即。

codeBlockerAwait,另一方面,仅当执行 await 时产生 returns。这发生在 consoleMusical("ameno") 完成执行之后。

如果你有一个更现实的例子,事情就会更加相似。例如,如果我们用异步函数替换阻塞 sleep 函数,您将获得预期的行为。

function sleep(seconds) {
  return new Promise(
    (resolve, reject) => {
      setTimeout(resolve, seconds * 1000);
    }
  );
}

const consoleMusical = async (letra) => {
  await sleep(1);
  console.log(letra);
};

async function codeBlockerAwait() {
  await consoleMusical("ameno");
  await consoleMusical("dorime");
  await consoleMusical("latiereno");
}

console.log(1);
codeBlockerAwait();
console.log(2);
console.log(3);