为何调用同步函数的JavaScript函数需声明async?
1. 为什么用了await的函数必须加async声明?
这是JavaScript的硬性语法规则:await关键字只能出现在被标记为async的函数内部——不管你函数里有没有调用异步逻辑,只要用了await,就必须给函数加async声明。
你代码里的add函数用了await asy(...),而asy返回的是一个Promise对象,await的作用是暂停当前函数的执行,直到这个Promise状态变为resolved、拿到返回值后再继续往下走。JS引擎规定这种暂停逻辑只能在async函数里生效,所以add必须加async,不然浏览器会直接抛出语法错误。
另外,async函数本身的特性是:不管内部逻辑如何,它的返回值都会被自动包装成一个Promise对象。这也是为什么你调用add()的时候,主线程不会被阻塞,后面的console.log('I will output FIRST...')会先执行——因为add()本质是启动了一个异步任务,自己跑到任务队列里排队去了。
2. 为什么没有sync声明,或者不能去掉async?
JavaScript里根本没有sync这个关键字,因为默认情况下,普通函数就是同步执行的。async是专门用来标记「包含异步等待逻辑(用了await)、或者返回Promise」的函数的,它是一个特殊标记,不是用来和「同步」对立的。
如果去掉async同时保留await,JS引擎会直接报错,因为它不知道该怎么处理这个await——毕竟只有async函数才具备暂停执行的能力。
3. 完全同步的代码需要放进async函数里吗?
完全不需要。同步代码直接写在全局作用域或者普通函数里就行,根本不需要包async函数。比如你写一段纯同步的计算:
function calculateSum() { const a = 3; const b = 4; const c = 5; console.log(a + b + c); } calculateSum(); console.log('同步代码会按顺序执行');
这段代码会先输出12,再输出后面的日志,完全是同步的,和async没有任何关系。
你代码里的console.log('I will output FIRST...')先执行,是因为add()是async函数,调用它会触发异步任务,主线程不会等它执行完,直接继续往下走。如果把所有代码都放进async函数里、同时去掉外面的日志,那函数内部的逻辑会按顺序执行,但整个函数本身还是异步的(因为是async函数)——不过如果内部没有任何异步操作,它会立即执行完。
附你提供的代码片段:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>async</title> </head> <body> <script type="text/javascript"> const asy = function (x, time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x) }, time) }) } const add = async function () { const a = await asy(3, 2000) console.log(a) const b = await asy(4, 5000) console.log(b) const c = await asy(5, 7000) console.log(c) const d = a + b + c console.log(d) } add(); console.log('I will output FIRST Even I am in BEHIND') </script> </body> </html>
内容的提问来源于stack exchange,提问作者James Wang

