1
noli 2017-02-13 21:17:23 +08:00 via iPhone
要求进一步详细信息: 能不能添加一点代码示例来表达情况?
|
2
dou4cc OP let s = 0;
(async () => { await Promise.resolve(); ++s; //2 })(); ++s; //1 |
3
dou4cc OP 我希望是这样:
let s = 0; (async () => { await Promise.resolve(); ++s; //1 })(); ++s; //2 |
4
morethansean 2017-02-13 21:27:56 +08:00
... 楼主, seriously?
|
5
dou4cc OP ?
|
6
dou4cc OP @morethansean ?
|
8
mooncakejs 2017-02-13 21:36:27 +08:00 via iPhone
你需要一个全局 async
|
9
sox 2017-02-13 21:50:37 +08:00
什么哲学,本来就该这样。。
|
10
xcodebuild 2017-02-13 22:12:57 +08:00
你的期望就不该这么写。。
|
11
zkd8907 2017-02-13 22:20:01 +08:00
竟然想顺序执行,为啥还要用 await/async 。。。没明白你想表达啥。
|
12
XDDD 2017-02-14 00:14:34 +08:00 via iPhone
async 的目的就是拆成两个 tick ,你的期望叫做 sync
|
13
FrankFang128 2017-02-14 00:16:57 +08:00 1
你的期望是错的……
|
14
dou4cc OP |
15
dou4cc OP 在某些场合我会对状态转移函数作缓冲,如果一个 tick 内又转移回来了便不触发状态改变的事件,上面的设计影响了我的缓存命中
|
16
Sparetire 2017-02-14 07:59:25 +08:00 via Android
异步是会传染的。。如果你希望全部按同步逻辑来写,那你应该用 async 包住整个逻辑
|
17
noli 2017-02-14 08:45:09 +08:00
@doucc
你期望的结果,跟你认为实际会发生的结果,在我认为的实际里面,实际上都有可能发生。 当然,一个异步结果很大可能总是会比下一个同步结果来得慢,但也并不是完全不可能得到相反的快慢结果。 所以你实际情景中遇到的问题是什么,请不要用自己的抽象来说明了,请直接一点吧。 |
19
dou4cc OP @noli 我的缓存机制是这样的,每过一个 tick 就回收一些缓存,所以两次操作间隔的 tick 越少能命中的缓存就越多
|
20
dou4cc OP 我非常不理解 await 对 tick 的极大浪费
|
22
fszaer 2017-02-14 09:32:27 +08:00
请问以下例子与 po 主所示代码中的异同
let s=0; (()=>{ setTimeout(()=>s++,0); })() ++s; |
23
xialdj 2017-02-14 09:33:45 +08:00 via iPhone
a();p.then(b);c(); 如果 p 已经被 resovled 那楼主的理解是不是执行顺序为 a b c ? 这个问题本质上和 await 是一致的
|
24
jkeylu 2017-02-14 09:51:13 +08:00
楼主想要的是下面这样的效果吗?其实调用 async 函数本质就是返回一个 promise
async function foo() { let s = 0; await (async () => { await Promise.resolve(); ++s; //2 })(); ++s; //1 } foo(); |
26
morethansean 2017-02-14 09:59:06 +08:00
await 怎么对 tick 有什么浪费了……
本质上这里涉及到的还是 Promise 的概念, Promise 的 then(f, r) 保证了 f 一定不是立即执行的(看起来像是异步),而是被立即入队。要是 then 一会儿是同步的一会儿是异步的,这对整个系统来说都是灾难好吗? 你都知道 async 关键字的意义,那么如果一定要实现你想实现的,肯定要把你的整个状态机都包含在 async function 内部啊……你想要用 async 的语法糖来让你的代码更方便一些,一会儿又在语法糖外面抱怨语法糖。你所谓的性能影响是因为你用了错误的方式造成了一些“意料之外”的结果,光是 then 将 f 入队本身没有什么严重的开销。 |
27
dou4cc OP @morethansean 我觉得 async function 应该节省 tick ,另实现一个时而异步时而同步的 then2 。健壮的程序可以应对时而同步时而异步的回调。
|
28
dou4cc OP @morethansean tick 本身确实开销不大,但节省 tick 可以带来的好处很多,除了我说的缓存机制,还有很多卡 tick 的事可以做
|
29
otakustay 2017-02-14 11:03:10 +08:00 2
jQuery 的 Deferred 最初就是你的这个模式,如果已经 resolved 则是同步的,否则会变成异步
但是这显然是不行的,从语言来说最重要的是一致性,即一个 Promise 你不应该需要知晓其当前状态(你看 Promise 本身也没有一个字段让你读状态),其当前状态应该不会影响你的任何逻辑,所以无论是否 resolved 其都必须是异步的 |
30
morethansean 2017-02-14 11:13:07 +08:00 1
@dou4cc 还是那句话啊,你大概在理解上有一点偏离了……
Promise 的设计本来就是需要保证异步的,不然这对使用者来说有极大的不稳定性需要考虑过于复杂的情形,甚至在有些场景下这将对整个代码结构都带来灾难性的破坏。 Promise then 本来就不是阻塞的不是同步代码,本来就是你所谓的 "tick" 模式。 then 把一个任务加入了队列,你的外部世界的语句本来就没处在 Promise 的范畴内,自然和这个任务也没有关系。 我们来看看你想要的结果,你想要的是: - 对一个 Promise 调用 then(f),如果这个 Promise 已经 resolve 了,那么 f 是立即执行的而不是被加入队列等当前的任务完成再执行。 如开头所说不这样的原因是,这让 Promise 变得不确定,实际生产中这会带来很大的问题( V2EX 上就会有一大堆人开始批判这个坑),没人会想用 Promise 。而且说实话,一个函数一会儿同步一会儿异步,这很怪异,我没见过。 可是你偏想要这么做,要提供一个 then2 ,满足这样的效果可以么?可以,当然可以啊(扩展一个 Promise 类,保存 Promise 的状态,调用 then 的时候检查一下然后做处理。对于 await ,虽然可能需要自己写处理器 polyfill 一下,在真正调用 await 之前检查一下 Promise 的状态),可是你真的需要这么做么?这就是大家关注的问题所在,我们可能认为你本来并不需要这样做(比如楼上有人提到你可能需要一个全局的 async 等等),所以认为你的理解是有偏差的。 你所谓的各种卡 "tick" 的好处,不是 then(f) 可以一会儿同步一会儿异步的理由。 |
31
fds 2017-02-14 11:28:53 +08:00
前面 @jkeylu 说的对,想保证执行顺序就是
let s = 0; await (async () => { await Promise.resolve(); ++s; //1 })(); ++s; //2 不过这跟 tick 没有关系,肯定是多个 tick 才能完成。 Premature optimization is the root of all evil -- DonaldKnuth |
32
rogerchen 2017-02-14 11:33:45 +08:00
明明是同步逻辑非要写成异步有什么办法。 await 了不交控制流出去难道阻塞着过年?
|
33
dou4cc OP @otakustay 我和你对一致性的理解有分歧,我认为健壮的程序无需 then 旳异步保证、同异步无本质区别。更显然地如果 then 实现成我说的,改成现在的会很方便:
Promise.all([p, new Promise(r => setTimeout(r, 0))]).then 即可,而从现在的实现改成我说的,就只能放弃 async function 改用 generator function 了 |
35
otakustay 2017-02-14 12:25:24 +08:00
最简单的例子,把你的代码改成一个比较现实的代码:
(async () => { let user = await fetchCurrentUserInfo(); console.log(1); })(); console.log(2); 请问你认为这个代码应该是 1 - 2 还是 2 - 1 还是任意都可以? |
36
limhiaoing 2017-02-14 13:11:58 +08:00 via iPhone
@morethansean
一会异步一会同步的你没见过不代表没有, C#的 async await 就是这样的。 |
37
limhiaoing 2017-02-14 13:21:39 +08:00 via iPhone
C#之类的这么做是从性能的角度考虑已经完成的同步执行性能会更好,比如从 socket 读一段数据,这个操作可能可以立即完成也可能无法立即完成。对于可以立即完成的完全可以同步执行,对于无法立即完成的才异步。
至于 node 为什么选择全异步就了解了。 |
38
limhiaoing 2017-02-14 13:22:20 +08:00 via iPhone
@limhiaoing 打错,最后一句少打了个不字。
|
39
morethansean 2017-02-14 13:30:14 +08:00 1
@limhiaoing 兄弟你要结合上下文不是这么断章取义的,我说的是作为 Promise 的一个 API , then 的执行一会儿是同步一会儿是异步。
给你一个 API readFile 然后告诉你这个 API 有可能是同步的有可能是异步的? 写 Promise 链的时候就不会关心你的业务逻辑具体是怎么执行的,你从缓存里直接读也好你发请求异步读也好,只是在我 method chain 中的一环而已我还要去关心你是同步异步的具体做了什么事?而且这里还并没有显示能够看到是同步还是异步的方法,只是做了一个函数调用而已。 Promise 本来是用来干嘛的,要解决什么问题,所以他这么设计了,把不稳定性和混乱引进来强行可以卡 tick 做很多的事情,关键是这些事情本来不是这么去做的。 |
40
morethansean 2017-02-14 14:02:58 +08:00
@limhiaoing 而且由于我不太清楚 C# 里面的 async/await 的实现,然而我简单地搜索了一下,包括 http://developer.51cto.com/art/201305/393992_all.htm 这篇文章,这样如果抛开 nodejs 和 C# 单 /多线程的区别的话,看起来并没有什么不同。文章中有提到 `await 关键处的代码片段是在线程池线程上执行` 并不是 GUI 线程。再者,搜了一下知呼,里面也提到 await 开始的那一刻 async 函数就返回了,其实都是编译器的语法糖而已。是我理解有问题吗……感觉不是很懂你的意思了……
|
41
limhiaoing 2017-02-14 14:52:02 +08:00 via iPhone
|
43
thuanqin 2017-02-14 16:14:00 +08:00
可能编译器可以直接处理这种情况将异步代码转为同步代码执行,不过会带来增加编译时间等开销吧。
|
44
jarlyyn 2017-02-14 16:19:56 +08:00
那么不想写异步代码楼主还是写 go 吧。
|
45
zhouyg 2017-02-14 16:34:33 +08:00
async 只是语法糖而已,本质还是 Promise ,既然是 Promise 那当然是异步的,因为 Promise 就是这么设计的。
|
46
Clarencep 2017-02-14 18:05:04 +08:00
|
47
limhiaoing 2017-02-14 21:34:50 +08:00
@morethansean
``` cs var task = Task.FromResult<int>(1 + 2); new Action(async () => { await task; Console.WriteLine("1"); })(); Console.WriteLine("2"); // Output: // 1 // 2 ``` ``` cs var task = Task.Delay(1); // delay 1ms new Action(async () => { await task; Console.WriteLine("1"); })(); Console.WriteLine("2"); // Output: // 2 // 1 ``` C#的 async 、 await 是这样的,立即可以完成(代码 1 )的,可以同步执行先输出 1 再输出 2 ,需要 1ms 才能完成的(代码 2 ),才必须异步先输出 2 再输出 1 。 C#应该是最早使用 async 、 await 语法糖的语言,之后才被各语言争相效仿(如果有更早的请指正),这种允许同步执行的 await 也被证明设计上没有错误,所以 ES7 如果是强制异步的话,就是设计哲学的问题了。 |
48
limhiaoing 2017-02-14 21:42:00 +08:00
@limhiaoing
而关于 future/promise 用于延后执行,可以看下这个。 http://en.cppreference.com/w/cpp/thread/async std::launch::deferred enable lazy evaluation |
49
xieranmaya 2017-02-14 23:40:08 +08:00
因为 Promise 的 resolved/rejected callback 是异步执行的。就将。
|