为什么我的异步/等待示例不起作用?

时间:2020-04-11 08:19:37

标签: javascript asynchronous async-await

我在理解async/await的整个概念时遇到了麻烦,并且花了很多时间阅读文档并尝试使用示例。但是我仍然不明白为什么这个小例子不起作用。

我想要的结果是让document.body.innerHTML包含文本“ 123”,因为doFirst()应该在doSomething()完成之前完成运行。

但是我总是得到“ 132”,好像我根本没有使用异步/等待。我在做什么错了?

async function doFirst() {
  document.body.innerHTML = document.body.innerHTML + "1";
  setTimeout(function() {
    document.body.innerHTML = document.body.innerHTML + "2";
  }, 500);
}

async function doSomething()
{
  await doFirst();
  document.body.innerHTML = document.body.innerHTML + "3";
}

doSomething();

很抱歉再次发布此帖子,上次我发布此问题时被标记为重复。因此,这一次我想澄清的是,我没有在寻找任何能告诉我如何正确执行操作的答案,而且还没有解释为什么为什么我的代码无法正常工作。

3 个答案:

答案 0 :(得分:4)

这是因为doFirst()返回了一个承诺,该承诺在计时器用尽之前已解决。与您的期望相反,setTimeout不会暂停脚本执行。

为了确保doFirst()在计时器用完后解析 ,您需要将整个函数包装在Promise对象中。计时器一旦用尽,就会调用resolve()方法,例如:

function doFirst() {
  return new Promise(resolve => {
    document.body.innerHTML = document.body.innerHTML + "1";
    setTimeout(function() {
      document.body.innerHTML = document.body.innerHTML + "2";
      resolve();
    }, 500);
  });
}

async function doSomething()
{
  await doFirst();
  document.body.innerHTML = document.body.innerHTML + "3";
}

doSomething();

如果您想避免使用callback hell,一种更干净的方法是简单地创建一个实用函数,该函数在setTimeout之后解析诺言,那么您可以等待从该函数返回的诺言进行打印,然后再打印“ 2 ”进入DOM:

// Utility function that resovles a promise after a given duration
function sleep(duration) {
  return new Promise(resolve => setTimeout(resolve, duration));
}

async function doFirst() {
  document.body.innerHTML = document.body.innerHTML + "1";
  await sleep(500);
  document.body.innerHTML = document.body.innerHTML + "2";
}

async function doSomething()
{
  await doFirst();
  document.body.innerHTML = document.body.innerHTML + "3";
}

doSomething();

答案 1 :(得分:2)

看看下面的代码:

npm install "@material-ui/lab"

您在做什么错?

您没有在yarn add "@material-ui/lab" 中返回承诺,因此该操作不是异步的(简而言之,您的代码 async function doFirst() { document.body.innerHTML = document.body.innerHTML + "1"; return myAsyncFunc(500) } function myAsyncFunc(delay) { return new Promise(resolve => setTimeout(function() { document.body.innerHTML = document.body.innerHTML + "2" resolve(); }, delay)); } async function doSomething() { await doFirst(); document.body.innerHTML = document.body.innerHTML + "3"; } 不会等待doFirst()完成并移至第{行) {1}})

注意:

  1. 如何立即运行doSomething()并返回doFirst()(基本上返回document.body.innerHTML = document.body.innerHTML + "3";)。

  2. 500毫秒后,document.body.innerHTML = document.body.innerHTML + "1";执行并运行myAsyncFunc。之后,返回下一行Promise,这标志着setTimeout要完成。

  3. document.body.innerHTML = document.body.innerHTML + "2"一旦返回return resolve()就结束了,因此添加了“ 3”

答案 2 :(得分:0)

我认为您可能对async关键字的功能有误解。尽管它具有名称,它并不能神奇地将函数更改为异步。它仅做以下两件事:

  1. 允许await在函数体内使用。
  2. 确保函数返回Promise。

但是只有当这两个一起使用时,它才真正有用。主体中没有await的异步函数根本不需要是异步的。

您的示例函数doFirst不使用await,因此它基本上等同于以下内容:

function doFirst() {
    document.body.innerHTML = document.body.innerHTML + "1";
    setTimeout(function() {
        document.body.innerHTML = document.body.innerHTML + "2";
    }, 500);
    return Promise.resolve(undefined);
}

如您所见,此代码没有异步的地方。 Promise.resolve返回一个可以立即解析为给定值的承诺。这意味着在await doFirst()中使用doSomething实际上不会等待任何事情,因为承诺已经解决。

您希望doFirst执行的操作是返回一个承诺,该承诺在执行setTimeout回调之前将无法解决。不幸的是,setTimeout没有返回承诺,因此您需要手动创建一个承诺:

function doFirst() {
    document.body.innerHTML = document.body.innerHTML + "1";
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            document.body.innerHTML = document.body.innerHTML + "2";
            resolve();
        }, 500);
    });
}

您可能会注意到这里不需要async关键字。这是因为该函数未使用await,而已经返回了一个Promise。 doSomething仍然可以使用await doFirst(),因为await可以与任何promise一起使用,而不仅是在调用异步函数时。

相关问题