es6引入generator的目的是什么,如何正确地使用generator?
发布于 8 年前 作者 youth7 8840 次浏览 来自 问答

最近在看generator的东西,发现大部分的介绍都是利用它来减少callback hell。但是我在 这个讨论中发现原来generator并不是设计用来处理异步编程/回掉的,它本质上应该是协程。我现在有这样的疑问: 1,generator的出现是为了解决什么问题,它的本质就是协程吗? 2,在什么样的场景下应该使用generator? (PS:我目前在项目中使用了大量的Promise来解决异步调用,写法看起来也很像是同步,例如 Promise.resolve() .then(doSomething1) .then(doSomething2) .then(doSomething3) .catch(catchError) 感觉这样代码可读性也好,不知道引入generator来改写会不会有什么好处)

7 回复

generator/yield跟同步都差远了,何况promise?

真正的同步应该是这样的

local fs = require('fs')
local name = fs.readFile('test.txt')
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
name = fs.readFile(name)
print(name)

generator就是用来模拟同步的,内里本质还是回调异步,也就是说你还是要用异步的思维方式去写异步程序,但可以用同步的方式来表达。

原来那种回调异步模式,代码时间长了,回过头来看,有可能出现自己都看不明白的危险。有了generator,同步表达就容易理解得多,但编码的时候还是偏向异步思维方式,需要透彻的理解回调异步。

最完美的异步模式是没有显式的异步,代码不需要generator/yield或者async/await的包装转换,就是直接写同步代码,思维方式也是同步的,也不需要理解回调异步。

generator就是用来模拟同步的 @coordcn 感觉generator不是专门为了这个目的而生啊。有一个说法是generator的本质是协程,也就是用户态线程,应该是用来处理多个逻辑流的,也就是模拟并发。

@youth7

@coordcn 的说法是对的

不知道我这样描述正不正确,你可以参考一下:

异步书写方式要转换成同步书写方式,面临的第一个问题就是如何在IO异步的时候,把执行权交出去让CPU继续执行其它event,协程就是一种解决方案

@youth7

generator不是专门为了模拟同步而生,但现在的情况是主要用来模拟同步了。

这涉及到语言本身的设计和使用问题,generator本来设计出来不是专门干这个的,但是设计出来之后结果就是主要干这个了,这就违背了设计者的初衷,所以ES7会有另一个语法糖补丁(async/await)来修正这个小问题。

generator和async/await都是语法糖,后者比前者更加符合语义,而且是自动执行的,不需要类似co这样的库来包装。但必须要注意,这两者只提供了协程的部分功能,我个人认为这并不是协程。这两者本质上是switch和goto的组合,状态和参数的传递通过共享变量(闭包等)实现,异步驱动还是依靠回调,为了使回调调用规范化,回调还得用promise包装下,也就是说,如果想要玩得好,必须有比较好的回调异步基础。

当然这样的模式广义上也可以算作协程的,只是实现的程度和方法不一样而已(有个)。而且这种方式由于没有独立的栈,性能上要比有独立栈的协程要好,因为协程切换需要保存和恢复寄存器,这种方式只是普通的函数调用而已。

总的来说,这种方式对异步编程有一定的帮助,现阶段还是很有必要的,但长远来说,必然会让位于纯粹的伪同步代码。

我个人正在朝这个方向努力 https://github.com/coordcn/LuaIO

你也可以看看 响马的javascript版本实现 http://fibjs.org/

你也可以看看 章亦春的nginx+lua实现 http://openresty.org/

lua这个阶段比javascript容易实现回调异步转形式同步,但lua也有自身弱点,字符处理能力不如javascript,但我认为字符处理主要还是正则,lua本身提供的正则只能是够用,但如果需要的话,可以做pcre绑定,lua与c的绑定是所有动态语言中最简单的,没有之一,主要有一定的c语言基础,半天就能学会。

@coordcn 那如果es7推出了async和await,那么promise和generator还能有什么用途呢?能不能大概讲一下generator设计的初衷? 还有就是lua不会,看不懂你的项目啊

@youth7

promise是一种规约,它将回调调用和错误处理规范化,便于generator或async/await使用,也就是说不管是generator还是async/await,promise是基础(只要你愿意,你自己也可以实现符合规约的回调调用)。我上面说的这种模式最大的问题是用异步的思想来写同步代码,只是在代码表达上有了进步,但思维方式还是异步的。如果要深入理解这种模式,回调异步还是要深刻理解的,这是基础,所以根本没有所谓有了async/await,generator和promise就没用的说法。

generator在所有可迭代的地方都可以用,回调异步转形式同步本质上也是迭代,只是这种迭代由事先注册好的回调来自动触发。

lua很简单的,和javascript相似度80%以上,都是函数式语言和命令式语言杂交的,lua相对来说更简单,如果你有javascript基础,静下心来看半天语法基本上就会了。我的项目是基于libuv的,libuv也是nodejs的核心,绑定语言不同而已,如果想深入了解nodejs,nodejs的代码是有必要浏览下的。

隔了多年再重新回来看 @coordcn 在第四楼的评论,才发现他对协程的理解真是到位,佩服佩服

回到顶部