异步回调最后谁赢了?
发布于 9 年前 作者 Hanggi 9184 次浏览 最后一次编辑是 8 年前 来自 问答

最近看了一些es6的异步处理方式,感觉挺有意思。 Promise、Async、Generator(thunk、promise)、co,提了一堆,但始终没看出哪个是最好的。 es6被越来越多得提起,iojs 3.0了,Node也快出4了,到底哪种方法能成为未来的主流?

46 回复

你用的顺手就好 不过generator肯定以后会越来越多 自豪地采用 CNodeJS ionic

这两个有什么区别:Promise, Generator(promise)?

@leapon 区别不大 但是promise和co一起确实能减少不少的麻烦 自豪地采用 CNodeJS ionic

国外测评是 bluebird最好

@wenshiqi0 我觉得都差不多,用某人的话就是:用一种复杂的方法解决另一个复杂的问题。

@leapon 实现Generator自动流程管理的几种方式。

nodejs 真是有意思,号称异步事件编程,结果大家都在怎么解决异步回调问题。反过来在类似于java, c#等这种同步思维的编程方式反而在解决异步事件编程来得更加简单,而在nodejs要解决同步编程怎么就是这么大的一件工程,各种解决方案,并且都解决的不完美。其实象async/wait感觉是目前最优美的解决方案,可是不知道为什么各个解决方案就不很快把这个方案落实,包括es6也是,居然还把async/wait拖到es7里去,其实如typescript也是,都没有优先考虑async/wait的方案。有点搞不明白。

没有赢家,只有跳出一个坑,跳进另一个坑,多年以后回头看看,青春的小鸟就这样飞走了

es6的异步方案:generator

就后端 js 来说,有哪门后端语言发展了好几年却还在解决流程控制问题? 就前端 js 来说,有哪门端的技术,发展了十几年却还在解决打包和分发的问题?

js 这个坑,深似海啊。。

@Hanggi 主要看你的理解 其实理解之后会变得比较容易 当然也就是坑浅了点

只能说将就用着吧,nodejs/js 最大的好好处就是生态太完善了,各种各样的库都有,你想要的基本上都能找到。

@pangguoming bluebird的速度据说是最快的 不过我自己用native promise重写了fromNode方法之后就可能不用bluebird了 太庞大了 总感觉用着不划算

用自己写的sas

@alsotang

实践出真知啊,这些都是大实话,用得越多,越深入,这种感觉会越明显。

javascript就是一个工程产物,虽然不是很完美,但却力求实用。

流程控制问题,在现在版本javascript下是很难有完美的解决方案的,都是过渡。

异步的终极目标应该是用同步代码写异步程序。

@coordcn 异步的代码运行是个 acyclic graph,我感觉只有最简单的单连接才适合用同步代码写异步程序。

@leapon

实现异步向同步的转换的关键在协程coroutine,es6的generator本质上和协程是类似的,但属于半调子,不彻底的,当然这么做也有苦衷,那就是为了兼容原来的回调代码。

每个客户端的链接就是一个协程,链接的建立和socket的传入可以用回调实现,然后接下来对socket的操作就跟同步代码一样了,在协程内部也能实现对外链接,链接返回的socket同样可以同步代码写。这样就把异步回调隐藏了起来,使程序看起来是同步的,而实质上是异步的,这样也就不需要依靠层层回调来保证程序的执行顺序。

我已经用lua+libuv实现了tcp模块,整个程序已经能够跑了,基本验证了我的想法。 https://github.com/coordcn/links http模块正在努力中,完成之后会正式分享。

最后的结果其实是,如果nodejs不变革,极有可能被形式同步取代,iojs看起来版本升得很快,但是实际上很多用户并不满意。

nodejs成也javascript,败也是javascript,这门语言包袱太重,太过灵活,看起来很多人都会,但用得好的人却是不多的。

作为nodejs的用户来说,大家其实并不喜欢回调模式下的异步,回调的目的是为了保证执行顺序,也就是同步,那我们何不直接来写同步的代码呢?对我们写代码的人来说,我们需要的不是异步代码,而是异步带来的性能上的好处,异步代码本身是恼人的。

@coordcn 真的很多? 自豪地采用 CNodeJS ionic

@coordcn 不知道为什么我没有这种感觉,反而觉得cb的方式代码看起来更清楚程序执行的时候是怎么回事,反而一些形式同步让代码看起来像是那样一步一步执行(而实际上又不是),反而不能透彻地理解自己的代码。

@fengmk2 @captainblue2013

难道你很满意?如果有的人非要认为回调就代表异步,我表示无法交流。持这种观点的人,其实连回调是什么作用都未必搞清楚,回调是保证执行顺序的,本质上是为了实现逻辑同步,那么我能用伪同步代码实现,为什非要套个回调?回调其实跟异步没有半毛钱关系,异步的本质是让别人去执行,让别人(别的CPU,网卡,显卡,线程)去执行完成后,继而调用的回调函数,这个过程才是异步的,如果还是自己执行,这个过程其实是同步的。所以回调代表不了异步,只是系统接口设计的时候恰巧设计成了回调函数。千万不可把回调当作一种信仰,nodejs会因此而受到伤害,nodejs发展初期就存在了coroutine和callback的争论,nodejs的作者坚定的反对coroutine,而现在es6却走向了coroutine,这难道不是讽刺和大势所趋么?这难道还需要争论么?

这个过程绝对不会因为个人的喜好而改变,有多少人愿意把本该用来写业务代码的时间花在处理流程控制上?这个世界上是熟练的写同步程序的程序员多还是异步的多?我跟@fengmk2 的讨论也不是一次两次了,@fengmk2 只要扪心自问,如果回调真的没问题,何必要有genertator,语言标准本身都在进化,人怎么能固步自封呢?

我们到底是要炫耀自己回调用得有多溜还是只是要异步带来的好处呢?现实情况是不管从编码难度还是性能上,用coroutine实现的伪同步都要好的多,而nodejs由于受到javascript语言本身的限制,虽然可以用generator实现伪同步,但你稍微调查一下,有多少人能真正理解koa?理解背后的原理?这中间的转换成本,用过的,被虐过的,大家心里都清楚。

@captainblue2013

我曾经也和你一样,认为异步必须是显式的,但经过仔细思考之后,我认为只要透彻的理解了异步的原理,形式其实是不重要的,我们只是需要异步带来的性能上的好处,对于异步表达本身,其实是越简单越好,如果非要做个区分,在函数名称上加个async不就行了?但我认为这样的标记都不是必须的。我们实现生活中大部分工作都是异步执行的,我们刻意去区分了么?

我个人觉得,回调和形式同步的讨论优劣已经没有必要了,答案nodejs和javascript已经给出了,如果回调真的可以包打天下,那就generator就没有出现的必要,promise都可以不要,koa也是多余的,现实是,有了更好的工具之后,大家都朝这个方向转。人的天性就是这样,总想偷懒,有同步代码不写,非要搞层层回调,那不是脑子坏掉了?

你应该了解过nginx lua module也就是openresty,我跟@fengmk2讨论也不是一次两次了,我现在东西已经写出来了,最先触动我,对nodejs回调模式下的异步产生怀疑的是fibjs,这是一个非常好的项目,但我对c++不是太懂,代码略读了下,感觉社区化难度比较大,几乎所有模块都是自己实现的。后来又看了luvit,这个项目完全是nodejs对lua的移植,在我看来没有任何价值。让我有信心觉得可以用纯同步代码实现异步程序的是openresty,原理很简单,代码一看就明白,我对c也比较熟悉,所以决定自己用lua和libuv实现一个,现在tcp模块已经实现,http正在进行,tcp测试结果是好于iojs的,lua我没用jit,而是用的5.3,后续如果对性能追求更极致的话,移植到luajit也很容易。

es6严重抄袭python 感觉就像写py一样 python没有所谓的copyright拿去就好 js的回调我写了一些 感觉callback hell 不过如此 7天一个星期 每天10个小时回调 就入手了 如果是按es6的写法写后端 我就回python 用tornado gevent什么的 感觉挺爽的 用js写没有回调的东西还真不习惯

@coordcn 我只是问了一句“iojs看起来版本升得很快,但是实际上很多用户并不满意。” 是否真的很多用户。你就说我认为callback这个好那个好,我有表达这个意思吗? 自豪地采用 CNodeJS ionic

@fengmk2

如果有的人非要怎么怎么样,这里并不是特指你,所以我并没有说你一定有这样的观点。

至于iojs用户满意不满意,iojs从哪些层面实现了大家亟需的功能,在性能优化,编程便利性上做了哪些改进,这些东西都可以来讨论。是不是真正做到了版本号与功能增进的匹配?如果一个基础库的版本号短时间内变化太快,这可不是什么好信号。

顺便说下,我只针对观点,不针对人。观点不同可以交流,可以用思想,也可以用代码。

我认为node和javascript必须做出改变,必须朝形式同步的方向发展,必须引入协程,否则,必然会被形式同步取代。

node是异步的先行者,libuv是非常棒的异步库,但这并不代表node就是异步的终结。

其他语言,其他框架都有机会超越,现在就是看谁的编程模型更直观,更容易理解。那些认为回调很简单,koa很简单的人,必须要明白,这是你们认为简单,在你们之外,还有千千万万个程序员在苦逼的堆同步代码,他们也想获得异步的好处,我们不能因为自己会了,成为了这个领域的高手,就莫名其妙的成了既得利益的捍卫者,我们程序员永远要做打破既得利益者,这才是我们的使命。

形式同步的时代一定会到来! https://github.com/coordcn/links

写python的感觉没什么不好啊? 如果tornado的异步生态丰富的话,我才不会非要用node呢😄

自豪地采用 fibjs

cb党表示要消灭你们这些异端。

习惯啊,显示的cb让我更容易理解整个流程的控制,现在往同步上走几个意思,让我看着同步的代码想着异步的思路?真是够了~

@arden 你说的这一点与“有一部分美食评论家并不会做饭,但热衷于讨论厨艺”是一个意思。

@tushiner

有些吃饭的也以为自己是厨子。。。

回调模式下的异步肯定会被形式同步取代的,这是大势所趋,nodejs如果不变,就会被淘汰,谁愿意花大量精力在流程控制上?

异步没有错,但回调模式下的异步肯定有问题,有更好的异步表达方式,为什么非要用层层回调来保证同步?

从纯粹的回调,到promise,再到genertor,再到async/await,这难道不是逐步去回调的过程么?javascript标准都在与时俱进,我们普通用户有什么理由继续把回调当个宝?

回调跟异步其实半毛钱关系都没有,回调代表不了异步。异步的实现形式也不仅仅是回调一条路。

@Hanggi 我也这么认为,干脆就不用了。。还可以提高效率

发现一个愤青,只要他一回复评论区就很长很长。。。

generator太别扭,async/await太遥远,目前还是promise(bluebird)好用,组合方便,错误处理比cb科学多了。我觉得try/catch块很难看!

来自酷炫的 CNodeMD

await async不错

@klesh 我也是这么认为的。我觉得promise在很多方面处理的都很不错,而且写起来很优雅

另外我也不喜欢async和await,仅仅是因为我不想再用try/catch来捕捉错误,如果用try/catch来捕捉错误的话,那么就会出现try/catch块的嵌套,这个可是比cb更可怕的东西

@chemdemo

不要乱给人扣帽子,评论长短不重要,关键得有内容,我写东西出来是给愿意看的人看的。

你要觉得我写得不对,指出来就是,没必要说一些怪话。

nodejs对一些人来说,已经不是一个技术了,而是信仰,是希望。。。

我这种不长眼的,就知道破坏气氛,自然也就被归为愤青,黑子,nodejs没入门,不会用的,初学者。

@coordcn 回调不一定只是用来处理异步, 显示的异步yield, 隐世的异步的小差距是否有那么大差距, 我看也未必,因人而异 我个人,用显示异步, 多了个yield关键字而已, 多敲几个字,还自动补全,没觉得很大的不方便

@151263

显式和隐式并不是问题的关键,如果非要做个区分,在每个函数加个async后缀就行了,这个效果跟加个关键字的确没什么两样。

nodejs现在已经向形式同步靠拢了,但在靠拢的过程中,nodejs回调的包袱甩不掉,原来的那些回调代码想要形式同步,必须做转换,这个转换过程还是有成本的。不管用thunkify还是promise都要转换,不然generator玩不起来。

编程模型的互相矛盾才是nodejs真正的问题,nodejs与v8衔接是回调模型,es6提供了promise和generator,可以实现形式同步,但这中间模型转换带来的思维方式的转换是避免不了的,nodejs现在就是底层是回调模型,上层通过generator框架提供形式同步(本质上还是回调调用,只是回调不在由自己调用,而是由框架代为调用)。nodejs的这个问题主要是历史造成的,现在要作出彻底的改变很难,这也就是所谓海量的库,其实是海量的包袱,里面只要用异步回调代码,就必须先做转换。

如果是依赖框架,依赖库做一些工作,这是没有区别,也没有多大问题的。大牛们做了很多工作,大家只要在他们的基础上写代码就是。如果要继续提升,你认为是统一的编程模型好还是两种冲突的编程模型好?你是愿意用一致的同步代码去实现异步,还是愿意用nodejs这种模式?

很多人对nodejs的感官还停留在以前,现在node不能再自己玩了,论性能,已经没有优势,论编程模型,nodejs已经落后于一些同步语言了。

用nodejs当然是看中了它的优点,库足够多,语法灵活,包管理机制强大 老是盯着缺点有什么劲呢 我要做cpu密集型的服务,我就用c++了 我要做高并发长连接服务器,我就用erlang了 谁没事非得在不属于它的领域较劲呢

不就是个流程控制吗。。。。。。 nodejs是比上不足,比下有余了,差不多了,没有coroutine也不是什么大不了的事,一个项目能否做成功,关键完全不在这里 c++,java里面如果遇到并发也是麻烦的很,要么回调,要么事件 当然c++也可以自己搞个coroutine,很简单,百来行代码,但是就一个coroutine的内核有个毛用啊,没有库可用

@qingfeng

终于有个明白人,知道nodejs有缺点啊。既然知道有缺点,就不要怕别人说出来,该用nodejs的人,自然用它的长处,用过的人,也自然知道它的缺点,但是就是有那么一帮人,不准别人说nodejs半点不好。

感觉是个大神,c++我不行,erlang没入门,couroutine大致知道原理,自己实现心里还是很虚的。

不就是个流程控制么?关键就是这个流程控制啊。版主在这个帖子回复中的两个经典的反问,其中一个就是说流程控制的。

@coordcn 但是浏览器的环境不是一般人所能控制的, 所以,浏览器一样逃不掉显示异步,一样逃不掉async关键字, 或许很久以后, W3C意识到了这个问题, 提供了这种模型的标准, 那么,等到那个时候,nodejs的V8引擎自然跟浏览器一样是 “同异步统一的编程模型”, 道理上很正确, 但有浏览器的存在, 说来说去, 却也逃不开必需得等待W3C的标准, 就像当初等待yield关键字一样

回到顶部