javascript Async await -await会阻止其他代码运行吗?

xhv8bpkk  于 2023-06-28  发布在  Java
关注(0)|答案(6)|浏览(181)

在javascript中,await是块代码吗?例如,假设我们有下面的代码:

async function queryDB() {
    const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")
    const selectUser = await promisePool.execute("SELECT User FROM Users") 
}
    • selectUser是否会等到addUser完成后才运行,以便我们选择添加的用户?**

另外,假设我们在waits之间添加一些不是promise的代码,类似这样:

async function queryDB() {
        const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")

setTimeout(() => console.log('Do something that takes 3 seconds'), 3000);

        const selectUser = await promisePool.execute("SELECT User FROM Users") 
    }
    • selectUser是否会等待addUser而不是setTimeout?如果是这样的话,您将如何编写上面的代码,使addUser首先运行,然后setTimeout,然后selectUser?**

我还想补充一点,我一直在研究和阅读stackoverflow和其他资源,但我需要一些澄清。

8tntrjer

8tntrjer1#

“selectUser”是否会等到addUser完成后才运行,以便我们可以选择添加的用户?
MDN Docs - await:
await表达式导致async函数执行暂停,直到Promise被解决(即,实现或拒绝),并在实现后恢复async函数的执行。当恢复时,await表达式的值是已实现的Promise的值。
queryDB函数的执行将暂停,等待第一个promise解决。第二行代码只有在第一行代码成功完成后才会执行。
“selectUser”是否会等待addUser而不是setTimeout?
是的,没错。
如果是这样的话,您将如何编写上面的代码,使addUser首先运行,然后setTimeout,然后selectUser?
您可以将setTimeout Package 在一个返回promise的函数中,然后等待该promise以确保在前两行完成后执行最后一行。
下面是 Package setTimeout的 Package 器函数的示例

function waitForTimeout(seconds) {
  return new Promise((resolve, reject) => {
     setTimeout(() => { 
        console.log("Hello World");
        resolve();
     }, seconds * 1000);        
  });
}

一旦你有了一个 Package 器函数,你可以await它,如下所示:

async function queryDB() {
    const addUser = await promisePool.execute(
        "INSERT INTO Users (User) VALUES ('username')"
    );

    await waitForTimeout(3);    // wait for 3 seconds

    const selectUser = await promisePool.execute("SELECT User FROM Users") 
}
zz2j4svz

zz2j4svz2#

重要提示:* * blocks**在这里可能是一个不好的词。更好的说法是等待。甚至更好的可能是说,使用await语法完成的操作可以保证按顺序执行。

    • 大局**

在Node中使用异步代码的主要原因是我们不会在等待一些异步操作(如数据库请求,网络请求,文件操作等)时阻止整个应用程序。- 我们只阻止这个特定的执行上下文。
尽管Node.js只使用一个线程来执行用户代码,但I/O操作是异步的,并且它们是非阻塞的。
因此,假设您有一个端点,上面展示的代码链接到前端的某个按钮“Add user”。

  • 比尔按下按钮,你开始处理请求,开始等待addUser操作
  • 这时约翰也按下了同样的按钮。您的代码仍然会被执行,并且也会开始等待,直到addUser完成。
  • 假设Users表陷入了死锁,任何数据库操作都会非常慢,我们有第三个用户Jane,她只是浏览您的网站,但她不需要登录/注册,所以她不碰Users表。发生了什么?简很好,她的要求会毫无问题地通过。
    • 如何等待setTimeout**

setTimeout来自“以前的时代”,所以它使用回调而不是异步/等待语法。但是如果你需要的话,总是可以将回调风格转换为async/await。

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
await delay(5000);
k10s72fa

k10s72fa3#

简而言之,await只阻塞当前异步函数中await语句之后的代码,而不是整个线程。一旦await被解决,剩下的代码就会被执行。在你的例子中,因为你有两个await语句,第二个语句在第一个语句完成之前不会运行,因为第一个语句阻塞了两个await语句所在的函数。对于第二个例子,由于setTimeout()没有返回promise,并且您也没有等待它,因此该函数将其视为“同步”操作。也就是说,它会将setTimeout()回调抛出到调用堆栈中,直到下一个事件循环,并继续执行下一行,这是另一个await语句,它将再次阻塞函数,直到它被解决。
为了一个接一个地执行这三行代码,你必须把setTimeout()放到一个promise中并等待它,这样JS就把它当作一个异步操作,并在进入下一行之前“等待”它完成。

t5fffqht

t5fffqht4#

selectUser是否会等到addUser完成后才运行,以便我们选择添加的用户?

是的

selectUser是否会等待addUser而不是setTimeout?如果是这样的话,您将如何编写上面的代码,使addUser首先运行,然后setTimeout,然后selectUser?

“selectUser”将在“addUser”之后执行,但不是setTimeout回调。如果你想在setTimeout之后运行“selectUser”,你可以在setTimeout回调函数中添加它。所以它应该看起来像:

async function queryDB() {
  const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")

  setTimeout(async () => {
    const selectUser = await promisePool.execute("SELECT User FROM Users");
  }, 3000);
}
qmb5sa22

qmb5sa225#

简短的回答是肯定的,它会阻塞。await的目的是确保下一行中有可用的结果。因此,如果您需要addUser的值来进行下一个查询,您将拥有它。
它的引入是为了让你不必在第一行的末尾写then(),并将第二个调用放入回调中,这会使代码难以阅读。

niwlg2el

niwlg2el6#

  • addUser* 被执行,当它返回一个Promise时,它被添加到微任务队列。

然后EventLoop检查JS调用堆栈是否为空/没有要执行的内容。然后它从MicroTask Queue中获取 addUser 并最终解决。
当这一切发生时,queryDB 被阻塞,因为使用了async await。
然后JS执行 setTimeout,并将回调附加到计时器(浏览器Web API)。
然后JS移动到 selectUser,因为它返回一个promise,所以它被添加到MicroTask Queue。
EventLoop再次检查JS调用堆栈是否为空或/没有要执行的内容。然后,它从MicroTask Queue中获取 selectUser,即使有一个计时器已经过期,并且 setTimeout 的回调函数在回调Queue中。因为微任务队列的优先级>回调队列。
为了避免这种情况,我们需要在JS中使用Promisification。使用 setTimeout 将其 Package 为Promise。以便在添加 selectUser 之前将其添加到微任务队列。
希望能帮上忙!

相关问题