generator函数初步学习
/ / 点击 / 阅读耗时 10 分钟看了许多材料后,感觉下面这三篇文章对于理解generator函数有非常大的帮助,囊括了常见用法、控制流程、循环操作等,理解的程度已经基本能满足现在的需求。
- https://davidwalsh.name/es6-generators
- https://davidwalsh.name/es6-generators-dive
- https://davidwalsh.name/async-generators
下面的内容为阅读材料时随手做的笔记,未经过整理。
关于generator函数的基本概念
这篇文章描述generator使用了...so powerful for the future of JS.
。
万万没想到!之前对generator的认知仅停留在是个新的函数种类,没想到这里厉害。
到目前已经遇到两种衍生的技术了:
async函数
saga结合成的redux-saga。
原文:
If you ‘ve ever read anything about concurrency or threaded programming, you may have seen the term ‘cooperative’, which basically indicates that a process(in our case, a function) itself chooses when it will allow an interruption, so that it can cooperate with other code. This concept is contrasted with ‘preemptive’, which suggests that a process/function could be interrupted against its will.
就是说,并行编程有两种,在一段程序运行的时候可以被打断,执行另一段程序,主动打断的称为 cooperative,被动打断的称为 preemptive。Generator函数就是前者,它通过yield
关键字,从generator函数内部打断执行过程,需要从外部恢复执行。
Generator函数并不仅仅是简单的打断、启动这种流程控制,它还允许向generator函数的内部和外部进行双向的数据传递。
创建iterator
调用一个generator函数便会创建一个iterator,并且创建的过程并不会执行generator函数中的内容。
关于generator的工作流程
以下内容出自此处。
- Advancing the Generator
使用next()函数
- Pass a Value To the Iterator
在function*函数中使用yield关键字
- Receive a Value From the Iterator
yield keyword can receive a value back from the iterator
1 | const generatorFunction = function* () { |
好奇怪,为啥执行第一个next不输出foo
,而是将这个值丢弃?
- 内部执行顺序
执行顺序
1 | var foo, f; |
执行结果
1 | tick 1 |
- 使用
for...of...
循环
准则:
- The iteration will continue as long as done property is false.
- The for..of loop cannot be used in cases where you need to pass in values to the generator steps.
- The for..of loop will throw away the return value.
- 委托yield
1 | let index; |
委托一个generator到另一个generator相当于将目标generator的函数体导入到目的generator中,
相当于下面这种代码形式:
1 | let index; |
- 用yield控制异步流程
1 | const foo = (name, callback) => { |
- 带错误处理的yield异步流程控制
1 | const foo = (parameters, callback) => { |
generator的一个理解角度
以下部分出自此处
翻译其中的understanding部分:
当一个函数被调用,其中的命令会一个接一个的按顺序执行,函数能够通过return
将一些值传给它的调用者。
1 | function regular() { |
generators
的出现能够像对待一个program
一样对待一个函数。这个函数能够根据你定义的规则执行。所以我们可以将这个generator
函数成为一个program
。
为了执行一个program
,我们需要一个interpreter
,这个interpreter
将“take the program in and run it”。
1 | interpreter(function* program() { |
yield
命令告诉一个program
跳出generator调到interpreter
中。program
和interpreter
的交流是双向的:
program
可以向interpreter
发送一些东西interpreter
也可以向program
返回一些东西
基于上面的描述,可以从下面的角度描述下面这行代码:
const a = yield b;
这行代码表示了我们如何发送一个命令b到interpreter
然后把它的结果给a。generator
函数将会暂停,直到interpreter
告诉它才会继续执行后面的代码。
从redux-saga的角度阐述这个概念。
redux-saga没有将side-effect
分散进多个action creator 和 reducer中,而是按逻辑组合多个片段行为,这个组合体被成为一个saga。
redux-saga中的helper
函数,相当于在翻译command
。
1 | function* welcomeSaga() { |
sagaMiddleware感觉就是一个interpreter。