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,上层所有函数都必须是异步函数?
1
janxin 2019-01-02 14:32:12 +08:00
当然不是,你还是可以用 promise 的那种写法,不需要 async 传染
|
2
oyosc 2019-01-02 14:38:20 +08:00
async 返回的就是一个 promise 对象,你也可以直接 then 来写
|
6
lrz0lrz 2019-01-02 14:49:53 +08:00
是这样的,async 是用来指定 await 的范围,如果没有 async,js 就不知道哪些代码需要等待 await 执行完成。
另外楼主这个例子,a 依赖 b 的结果,b 的结果依赖 c 的结果,c 的结果依赖异步的结果,所以 a 依赖异步的结果,理应是异步的呀? |
7
shintendo 2019-01-02 14:52:05 +08:00
你想要哪一层用 await,就在那一层用 async,与上一层无关,上一层仍然可以 promise
如果你想要每一层都 await,自然每一层都要 async async/await 不过是语法糖,再牛逼也不能真的把异步变同步啊 |
8
sagaxu 2019-01-02 14:52:42 +08:00 via Android
await 只能出现在 async 函数內,但是普通函数可以调用 async 函数
|
9
geelaw 2019-01-02 14:53:22 +08:00 via iPhone 2
async 的作用是启用该 context 内的自动 CPS 变换(也就是同步风格代码翻译成异步),await 的作用是表明这里是一个 CPS 变换的 checkpoint。
用同步的风格写异步的代码 = 用 await,从而包裹之的 function 必须用 async 修饰(也就是“启用 await ”)。 ES 的 async/await 和 C# 的一样。 |
10
CloudnuY 2019-01-02 14:54:15 +08:00
你让一个人帮你去楼下买东西,你必须在楼上等着他买回来,总不能自己出去逛街吧……
|
11
autoxbc 2019-01-02 14:57:11 +08:00
async 传染的本质:对于末端是异步的函数,在整个调用链上,从分界点(同步函数以同步形式调用异步函数)开始,到末端,要全部显式声明 async
a -> b -> c(以同步形式调用 d) -> d(异步) -> e(异步) -> f(异步) d,e,f 必须是 async ; a,b,c 完全不需要 到底哪一层需要是异步函数,取决于程序到底可以在哪个位置并行,必然存在这么个分界点 |
12
cstome OP |
13
wyz123723 2019-01-02 15:01:36 +08:00
看你是想写成异步还是同步了。想写成同步,也就是下一句必须等待上一句执行完毕才能执行,那就得用 await,也就必须用 async。如果你想写成异步,那就写成 then 的形式,也就不需要加 async 了。
|
15
zbinlin 2019-01-02 15:06:15 +08:00
@cstome
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(..., ...); |
17
zbinlin 2019-01-02 15:11:38 +08:00
@cstome
function A() { return B(); } async function B() { let someData = await C(); //Some logic code return someResult; } function C() { return new Promise(); } A().then(..., ...) |
18
cstome OP @wyz123723 #13 我就是想要同步的。
比方说我用 axios 请求数据,必须根据请求结果才能进行判断,执行下一步。 如果用 Promise 方法就只能一直 then 下去,感觉整个程序都是写在 then 里,不优雅。 然而用了 async/await 发现这个问题。 |
20
wyz123723 2019-01-02 15:19:59 +08:00
|
21
autoxbc 2019-01-02 15:20:28 +08:00
@cstome #14
如果 c 不需要 d 的返回值(既不需要异步状态的真实返回值,也不需要同步状态的 promise ),c 就是分界点 async function d(){} function c(){ d(); } 你的例子无法改写,分界点在更高的位置。上面说用 promise 改写的理解有误,用了 async 和 await 就不应在调用链里写任何 promise |
22
cstome OP @zbinlin #19 加入我在 A 里面也需要获取 B 的结果在进行处理呢?
还是不可避免的要把 A 变成异步函数。 又或者使用 Promise 的话,就只能把后面的逻辑都写在 then 里: ```js function A() { B().then(res => { //some logic return someResult; }) } ``` 这样看起来就是不太好。。。 |
25
jin5354 2019-01-02 15:56:05 +08:00
@cstome C 是个异步函数,B 调用了 C 且依赖 C 的返回值,那 B 肯定也是异步函数啊,同理 A,async/await 关键字就是在表明本函数是异步函数,但是可用类同步的姿势写,不可能跟同步写的一模一样的,设计出来就不是完全无感知的,你原文写法没毛病
|
26
shintendo 2019-01-02 16:00:36 +08:00
A 是否要等待 B 的结果,和 B 是否要等待 C 的结果,是两个不相关的异步事件,你想把哪个写成同步,就对哪个用 async/await,不能指望写了其中一个,另一个也自动变成同步了呀。
|
27
otakustay 2019-01-02 16:37:13 +08:00
async 就是个标记,当你需要等一个异步函数的时候,无论它的调用方是不是 async,都注定是异步了(用 promise 的 then 也一样是异步)
|
28
abc635073826 2019-01-02 16:44:36 +08:00
@CloudnuY 只有你说到了重点🌚
|
29
cstome OP |
31
lzvezr 2019-01-02 18:29:44 +08:00 via Android
你可以直接 return 一个 promise,在 then 里面 return 最终会被捕获
```评论不支持 markdown function A() { return B().then(res => { //some logic return someResult; }) } await A() 最终得到的是 someResult |
32
shynome 2019-01-02 18:30:28 +08:00 via Android
别用 async 和 Promise 了, cb 一直写下去吧,性能又好
对的就是有传染性,就是要 async 的 |
33
ayase252 2019-01-02 18:39:45 +08:00 via iPhone
一个函数里有一个异步操作就是异步啊,没毛病啊。
|
34
sagaxu 2019-01-02 19:33:12 +08:00 via Android
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function
async function expression used as an IIFE,你可以用 IIFE 斩断这种传染性。 |
35
sagaxu 2019-01-02 19:38:40 +08:00 via Android
function a() {
(async () => { // 此处可以 await })(); } a 是一个没有 async 的函数,a 里面使用了 await |
37
kcats 2019-01-02 19:51:04 +08:00
tc39 有个新的提议: top level await, 参见 https://github.com/tc39/proposal-top-level-await , 目前是 stage 2, 最新版 v8 已经实现了这个 proposal, 所以你可以在 chrome 控制台直接写 await 1 回车测试.
|
39
des 2019-01-02 22:53:57 +08:00 via Android
虽然不是上层必须 async,但还是 async 舒服。
不传染的话,你就得自己等待返回结果,然后处理 顺便提一下一个有意思的东西,fibjs,就是为了解决这些的 |
40
TwoDays91 2019-01-03 08:11:00 +08:00 via iPhone
如果你逻辑依赖异步那你只能这么写,你还没试过每个 async 都要写 try catch。建议风格统一不要 promise 混着用。
|
42
DOLLOR 2019-01-03 08:33:56 +08:00 via Android
callback, Promise, async function 都有传染性,只是语法糖甜度不同,该异步的仍要异步
|
43
abc635073826 2019-01-03 15:12:02 +08:00
@cstome 本质上东西回来了你是要拿到的,它总有一个归属地
|
44
kcats 2019-01-03 15:16:08 +08:00
@jjx 这是正常的吧, 一个异步的函数在外部还能搞成同步的? 那异步的作用有啥意义? 楼主的问题是自己没想清楚, top level await 解决的问题是在没有 async 函数标记的情况下同步写异步代码, 和楼主的问题是两码事.
|
45
cstome OP |
46
kcats 2019-01-03 16:24:03 +08:00
@cstome 这个只是语法(内部处理机制)上的不同. 之前有和一个做 cdn 的哥们讨论过, 他习惯于写 go 和 lua, 这两个语言都有 routine 的概念, io 操作都是异步的, 但是都是同步的写法. 这和 js 就是两个极端. js 本质上暴露给用户的就是一个纯异步的环境, async/await 只是一个语法糖, 把回调变成的同步的写法. 但是本质是没有变的. 因为 js 的函数栈与事件循环机制, 决定了只有一个调用栈被清空了之后, 才能够执行下一个事务. async/await 本质上还是回调, 相当于是把后续的代码分块了, 和 python 的 event 有点类似. 说白了 async/await 就是提供了一个标记, 既是给开发人员看的, 也是给解释器看的. 如果没有这个标记还要实现相同的效果, 那整个 js 的机制和 API 规范都要改了.
|
47
Sapp 2019-01-24 10:17:52 +08:00
同步如何能拿到异步的返回值?要么回调,要么把异步转为同步啊... 你的 b 一旦调用了 c,他就是个异步了,a 调用 b 也成了异步,你想拿到 a 返回的值,必然要么回调,要么把 a 转同步
|
48
libook 2019-01-29 15:53:41 +08:00
因为 A 必须依赖 B 执行完才可以继续执行,同时 B 也依赖 C 执行完才能继续执行,所以不管你用 callback 还是 Promise 还是 async,都逃不掉三者都做同步化处理:
callback 版本: function A(resultFromB) { let someData = resultFromB; return someResult; } function B(resultFromC, cb) { let someData = resultFromC; //Some logic code cb(someResult); } function C(cb) { (new Promise()).then((result) => { cb(result, A); }); } C(B); Promise 版本: function A(resultFromA) { let someData = resultFromA; return someData; } function B(resutlFromC) { let someData = resutlFromC; //Some logic code return someResult; } function C() { return new Promise(); } C.then(B).then(A).then((resultFromA) => { //Do something. }); 避免不了的,但是外层层都用 async 不是因为内层用了 async,而是因为外层关心内层执行完的结果,如果不关心的话完全可以不用 async。 function B() { new Promise(); } function A() { B();//我不关心 B 执行完返回啥,就让他自生自灭吧 //继续执行其他的代码 } A(); |