问题
In javascript, does await block code? For example, let's say we have the below code:
async function queryDB() {
const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")
const selectUser = await promisePool.execute("SELECT User FROM Users")
}
Will "selectUser" wait to run until addUser is finished so that we can select the user that is added?
Also, let's say that we add some code between the awaits that is not a promise, something like this:
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")
}
Will "selectUser" wait for addUser but not the setTimeout? If so, how would you write the above code to make addUser run first, then setTimeout and then selectUser?
I would also like to add that I have been studying and reading on both stackoverflow and other resources, but I need some clarification.
回答1:
Will "selectUser" wait to run until addUser is finished so that we can select the user that is added?
From MDN Docs - await:
The await expression causes async function execution to pause until a Promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise.
Execution of queryDB
function will be paused while it waits for the first promise to settle. Second line of code will only execute after first one has completed successfully.
Will "selectUser" wait for addUser but not the setTimeout?
Yes, that is correct.
If so, how would you write the above code to make addUser run first, then setTimeout and then selectUser?
You could wrap setTimeout
in a function that returns a promise and then await that promise to make sure last line executes after first two have completed.
Following is an example of wrapper function that wraps setTimeout
function waitForTimeout(seconds) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Hello World");
resolve();
}, seconds * 1000);
});
}
Once you have a wrapper function, you can await
it as shown below:
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")
}
回答2:
Will "selectUser" wait to run until addUser is finished so that we can select the user that is added?
Yes.
Will "selectUser" wait for addUser but not the setTimeout? If so, how would you write the above code to make addUser run first, then setTimeout and then selectUser?
"selectUser" will be executed after "addUser", but not the setTimeout callback. If you want to run "selectUser" after setTimeout, you can add it inside the setTimeout callback function. So it should look like:
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);
}
回答3:
Short answer is yes, it blocks. The purpose of await is, to make sure you have the result available in the next line. So if you needed the value of addUser to make the next query, you would have it.
It was introduced so you don't have to write then() at the end of the first line and put the second call into a callback, which makes the code hard to read.
回答4:
Important note: blocks is probably a bad word here. A better word is it waits. Even better would be probably to just say that operations that are done using await
syntax are guaranteed to be executed sequentially.
The Big Picture
The main reason for using asynchronous code in Node is that we don't block the whole app while we wait for some asynchronous operation like a database request, a network request, a file operation etc. - we only block this particular execution context.
Even though Node.js only uses one thread for executing user code, but I/O operations are asynchronous and they're non-blocking.
So imagine you have an endpoint with the code that you presented above, that is linked to some button "Add user" on the front end.
- Bill presses the button, you start handling the request, start waiting for
addUser
operation - At this point John also presses same button. Your code will still be executed and will also start to wait until
addUser
finishes. - Let's say that
Users
table has gotten into a deadlock and any db operations with it will be super slow, and we have a third user, Jane, who is just browsing your site but she doesn't need to sign in/sign up, so she doesn't touchUsers
table. What happens? Jane is totally fine, her requests will go through without any issues.
How to await setTimeout
setTimeout
is coming from "previous era" so it uses callback instead of async/await syntax. But it is always possible to convert callback style to async/await, if you need it.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
await delay(5000);
来源:https://stackoverflow.com/questions/65478269/async-await-does-await-block-other-code-from-running