技术解析

ES 中要用 await,上一层的函数都要是 async 的?
0
2021-09-02 02:03:50
idczone
async function A() {
    let someData = await B();
    
    return someData;
}

async function B() {
    let someData = await C();
    
    //Some logic code
    return someResult;
}

async function C() {
    return new Promise();
}

A();

上面实例的,只有 C 是异步的,B 在调用 C 同步执行的时候,B 必须是异步函数。而 A()在调用 B 时需要 B 通过 C 的返回经过 B 的某些计算,再返回给 A,因此调用 B 的时候也要是同步的。想要让 B 同步,A 就必须是异步函数。

这样的话岂不是想要用 await,上层所有函数都必须是异步函数?


当然不是,你还是可以用 promise 的那种写法,不需要 async 传染

async 返回的就是一个 promise 对象,你也可以直接 then 来写



我知道,但是这样似乎还是没法优雅的解决回调的问题。

promise 不就是为了解决回调提出来的方法么?

相对于回调地狱这种来说,已经很优雅了,更直观的表示,如果你是指完全的同步这种问题,那应该是没有...

是这样的,async 是用来指定 await 的范围,如果没有 async,js 就不知道哪些代码需要等待 await 执行完成。
另外楼主这个例子,a 依赖 b 的结果,b 的结果依赖 c 的结果,c 的结果依赖异步的结果,所以 a 依赖异步的结果,理应是异步的呀?

你想要哪一层用 await,就在那一层用 async,与上一层无关,上一层仍然可以 promise
如果你想要每一层都 await,自然每一层都要 async
async/await 不过是语法糖,再牛逼也不能真的把异步变同步啊

await 只能出现在 async 函数內,但是普通函数可以调用 async 函数

async 的作用是启用该 context 内的自动 CPS 变换(也就是同步风格代码翻译成异步),await 的作用是表明这里是一个 CPS 变换的 checkpoint。
用同步的风格写异步的代码 = 用 await,从而包裹之的 function 必须用 async 修饰(也就是“启用 await ”)。
ES 的 async/await 和 C的一样。

你让一个人帮你去楼下买东西,你必须在楼上等着他买回来,总不能自己出去逛街吧……

async 传染的本质:对于末端是异步的函数,在整个调用链上,从分界点(同步函数以同步形式调用异步函数)开始,到末端,要全部显式声明 async
a -> b -> c(以同步形式调用 d) -> d(异步) -> e(异步) -> f(异步)
d,e,f 必须是 async ; a,b,c 完全不需要
到底哪一层需要是异步函数,取决于程序到底可以在哪个位置并行,必然存在这么个分界点



仔细想了一下,你们所说的改成 Promise 是怎么改?
能拿我的例子改一下吗?
改成这样?
```
function A() {
let someData = B().then(res => {
return res;
})
}
function B() {
let someData = C().then(res => {
//Some logic code
return someResult;
})
}
async function C() {
return new Promise();
}
A();
```

看你是想写成异步还是同步了。想写成同步,也就是下一句必须等待上一句执行完毕才能执行,那就得用 await,也就必须用 async。如果你想写成异步,那就写成 then 的形式,也就不需要加 async 了。

此时 c 要怎样用同步的方式调用异步?
如果用 await 的话显然不行。


async function A() {
return B();
}
async function B() {
let someData = await C();

//Some logic code
return someResult;
}
async function C() {
return new Promise();
}
A().then(..., ...);

这样岂不是还是每一层都用 async


function A() {
return B();
}
async function B() {
let someData = await C();
//Some logic code
return someResult;
}
function C() {
return new Promise();
}
A().then(..., ...)

我就是想要同步的。
比方说我用 axios 请求数据,必须根据请求结果才能进行判断,执行下一步。
如果用 Promise 方法就只能一直 then 下去,感觉整个程序都是写在 then 里,不优雅。
然而用了 async/await 发现这个问题。

只要函数内有 await 才必须使用 async 定义

那就必须加 async 了
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function#%E6%8F%8F%E8%BF%B0


如果 c 不需要 d 的返回值(既不需要异步状态的真实返回值,也不需要同步状态的 promise ),c 就是分界点
async function d(){}
function c(){
d();
}
你的例子无法改写,分界点在更高的位置。上面说用 promise 改写的理解有误,用了 async 和 await 就不应在调用链里写任何 promise

加入我在 A 里面也需要获取 B 的结果在进行处理呢?
还是不可避免的要把 A 变成异步函数。
又或者使用 Promise 的话,就只能把后面的逻辑都写在 then 里:
```js
function A() {
B().then(res => {
//some logic
return someResult;
})
}
```
这样看起来就是不太好。。。

这就是显示切换的缺点,想兼容不想大改只有用这种方式

使用 async 函数有什么影响吗(不好的地方)?

C 是个异步函数,B 调用了 C 且依赖 C 的返回值,那 B 肯定也是异步函数啊,同理 A,async/await 关键字就是在表明本函数是异步函数,但是可用类同步的姿势写,不可能跟同步写的一模一样的,设计出来就不是完全无感知的,你原文写法没毛病

A 是否要等待 B 的结果,和 B 是否要等待 C 的结果,是两个不相关的异步事件,你想把哪个写成同步,就对哪个用 async/await,不能指望写了其中一个,另一个也自动变成同步了呀。

async 就是个标记,当你需要等一个异步函数的时候,无论它的调用方是不是 async,都注定是异步了(用 promise 的 then 也一样是异步)

只有你说到了重点
数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服