英文:
Syntax question: Why is it necessary to define a function as async in JS?
问题
这只是一个简单的问题。我们有await
关键字,允许函数在继续执行之前返回结果。当然,你也可以以相同的方式使用Promises,但我在这个问题中特别关注async。
在以下上下文中,async函数会出现:
const funcA = async newValue => {
await connection.query(`UPDATE t SET field = ?`, [newValue])
.catch(error => console.log(error));
const valueA = await connection.query(`SELECT t.field FROM t LIMIT 1`)
.then(([results, fields]) => (results?.[0] ?? null))
.catch(error => console.log(error));
console.log(valueA.field);
};
funcA("test");
不使用async的执行类似方法如下:
const funcA = newValue => {
connection.query(`UPDATE t SET field = ?`, [newValue])
.then(() => connection.query(`SELECT t.field FROM t LIMIT 1`))
.then(([results, fields]) => (results?.[0] ?? null));
.then(valueA => console.log(valueA.field))
.catch(error => console.log(error));
};
funcA("test");
现在忽略这个示例代码的实用性,只关注功能,为什么我们需要在定义函数之前使用async
关键字呢?为什么不允许在每个函数中使用await
。第二个示例可以加上async
关键字,但它不会有任何不同,因为Promises在两个上下文中的工作方式相同。我们是否可以完全消除async
关键字呢?
我相信我肯定是在这里漏掉了什么,但我不知道背后的原因。
英文:
It's a simple question. We have the await
keyword which allows the function execution to return a result before continuing. Of course you can use promises in the same way, but I'm specifically interested in async in this question.
An async function would appear in the following context.
const funcA = async newValue => {
await connection.query(`UPDATE t SET field = ?`, [newValue])
.catch(error => console.log(error));
const valueA = await connection.query(`SELECT t.field FROM t LIMIT 1`)
.then(([results, fields]) => (results?.[0] ?? null))
.catch(error => console.log(error));
console.log(valueA.field);
};
funcA("test");
A similar method of executing this without async would be
const funcA = newValue => {
connection.query(`UPDATE t SET field = ?`, [newValue])
.then(() => connection.query(`SELECT t.field FROM t LIMIT 1`))
.then(([results, fields]) => (results?.[0] ?? null));
.then(valueA => console.log(valueA.field))
.catch(error => console.log(error));
};
funcA("test");
Now ignoring the practicality of this example code, and just focusing on the functionality, why do we need to use the async
keyword before defining the function at all? Why not allow await
in every function. The second example could have the async
keyword but it wouldn't work any differently because promises work the same in both contexts. Couldn't we just eliminate the async
keyword entirely?
I'm certain I must be missing something here but I don't know the reasoning behind it.
答案1
得分: 1
好的,这应该不被视为权威答案,更像是一种民间传统回答。
当代码调用函数时,就像我们的祖父母调用函数:
let x = f();
函数被调用,它执行它的任务,并将其返回值赋给 x。
现在让我们谈谈 async
函数。这样的函数旨在帮助处理异步操作调用的顺序问题。以前,这需要构建一系列的 .then()
、回调和 .catch()
来实现。那样能够工作,但容易令人困惑且容易出错。
async
和 await
提供的是处理这种 Promise 操作序列的抽象。在底层,Promise 机制仍然做着同样的事情。一个可以考虑的方法(并非完全准确)是,await
操作符将其后的代码转化为一个 .then()
回调函数。
因为单个 async
函数可能在内部有许多 await
调用,当在某个上下文中使用 await
调用它时,我们必须处理单个调用可能返回一个接着一个的 Promise 的情况:
const af = async function() {
let val = await a();
val = await b(val);
val = await c(val);
return val;
}
在 async
函数内部的每个 await
都会返回一个 Promise。但考虑调用 af
:
let foo = await af();
为了评估它,函数内部 await
表达式返回的三个 Promise 对象必须依次完成,然后调用上下文中的代码才能继续执行后续语句。
好的,现在,如果你还没有慌乱,你可以 await
任何你想要的东西:
let d = await Date.now();
这样也可以正常工作。d
的值将是一个 Promise,因为如果等待的表达式不是 Promise,实际上你会得到:
let d = Promise.resolve().then(_ => Date.now());
当然 d
仍然是一个 Promise,这有点混乱。
另外,你可以调用一个 async
函数而不使用 await
,这也没问题,只要你意识到你会得到一个 Promise。
因为这些东西很难用精确的机械细节来解释,对我来说最好养成坚持使用 async
和 await
并遵循规则的习惯。除非你真的需要,不要混合 .then()
的代码进去。容易忘记返回 Promise .then()
链的结果。使用 async
和 await
,你只需要关心你调用的函数,它们要么是明确地 async
,要么是你知道会返回 Promise 对象的函数(因为在这种情况下 await
也能正常工作)。
英文:
OK this should not be taken as an authoritative answer. More like a folk tradition answer.
When code calls a function the way our grandparents called functions:
let x = f();
the function is invoked, it does what it does, and its return value is assigned to x.
Now let's talk about an async
function. Such functions are intended to help deal with the problem of sequencing calls to asynchronous operations. Formerly, that required constructing chains of .then()
and callbacks, and .catch()
for exceptions. That works, but it's confusing and error-prone.
What async
and await
provide is an abstraction around handling that kind of Promise sequence of operations. Underneath, the Promise mechanism still does the same thing. A way to think about it (that is not entirely accurate) is that the await
operator turns the code that follows it into a .then()
callback for you.
Because a single async
function may have many await
calls internally, when it is called with await
from some context, there we have to handle the fact that the single call may return Promise after Promise:
const af = async function() {
let val = await a();
val = await b(val);
val = await c(val);
return val;
}
Each await
inside the async
function will return a Promise. But consider calling af
:
let foo = await af();
To evaluate that, the three Promise objects returned from the await
expressions within the function must all complete, one after the other, before the code in the calling context can move on to the subsequent statements.
OK, now, if your hair is not on fire yet, it is possible to await
anything you want:
let d = await Date.now();
That works fine. The value of d
will be a Promise, because if the expression that's awaited isn't a Promise you effectively get
let d = Promise.resolve().then(_ => Date.now());
Of course d
will still be a Promise, and that's kind-of a mess.
Also, you can call an async
function without await
and that's fine, as long as you realize that you're getting a Promise back.
Because this stuff is really hard to explain in precise mechanical detail, to me it's better to be in the habit of sticking with async
and await
and following the rules. Don't mix .then()
code into the mix unless you really need to. It's easy to forget to return the result of a Promise .then()
chain. With async
and await
, all you have to worry about is keeping track of the functions you're calling that are either explicitly async
or that you know will return Promise objects (because await
will work fine in that case too).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论