1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

修改generator

This commit is contained in:
Ruan Yifeng 2015-01-04 10:57:26 +08:00
parent fa53528312
commit a7a7fdaa62

View File

@ -4,7 +4,7 @@
### 简介
所谓Generator有多种理解角度。首先可以把它理解成一个内部状态的遍历器每调用一次内部状态发生一次改变可以理解成发生某些事件。ES6引入Generator函数作用就是可以完全控制内部状态的变化依次遍历这些状态。
所谓Generator有多种理解角度。首先可以把它理解成一个函数的内部状态的遍历器,每调用一次,函数的内部状态发生一次改变可以理解成发生某些事件。ES6引入Generator函数作用就是可以完全控制函数的内部状态的变化,依次遍历这些状态。
在形式上Generator是一个普通函数但是有两个特征。一是function命令与函数名之间有一个星号二是函数体内部使用yield语句定义遍历器的每个成员即不同的内部状态yield语句在英语里的意思就是“产出”
@ -97,6 +97,8 @@ g.next(true) // { value: 0, done: false }
上面代码先定义了一个可以无限运行的Generator函数f如果next方法没有参数每次运行到yield语句变量reset的值总是undefined。当next方法带一个参数true时当前的变量reset就被重置为这个参数即true因此i会等于-1下一轮循环就会从-1开始递增。
这个功能有很重要的语法意义。Generator函数从暂停状态到恢复运行它的上下文状态context是不变的。通过next方法的参数就有办法在Generator函数开始运行之后继续向函数体内部注入值。也就是说可以在Generator函数运行的不同阶段从外部向内部注入不同的值从而调整函数行为。
再看一个例子。
```javascript
@ -425,9 +427,9 @@ var clock = function*(_) {
协程coroutine是一种程序运行的方式。传统的“子例程”subroutine采用堆栈式“后进先出”的执行方式只有当调用的子函数完全执行完毕才会结束执行父函数。协程与其不同多个函数可以并行执行但是只有一个函数处于正在运行的状态其他函数都处于暂停态suspended函数之间可以交换执行权。也就是说一个函数执行到一半可以暂停执行将执行权交给另一个函数等到稍后收回执行权的时候再恢复执行。这种可以并行执行、交换执行权的函数就称为协程。
不难看出,协程适合用于多任务运行的环境。在这个意义上,它与线程很相似,都有自己的执行上下文、可以分享全局变量。它们的不同之处在于,同一时间可以有多个线程处于运行状态,但是运行的协程只能有一个,其他都处于暂停状态。此外,线程是抢先式的,到底哪个线程优先得到资源,必须由运行环境决定,但是协程是合作式的,执行权由协程自己分配。
不难看出,协程适合用于多任务运行的环境。在这个意义上,它与线程很相似,都有自己的执行上下文、可以分享全局变量。它们的不同之处在于,同一时间可以有多个线程处于运行状态,但是运行的协程只能有一个,其他都处于暂停状态。此外,线程是抢先式的,到底哪个线程优先得到资源,必须由运行环境决定,但是协程是合作式的,执行权由协程自己分配。从实现上看在内存中子例程只使用一个栈stack而协程是同时存在多个栈但只有一个栈是在运行状态也就是说协程是以多占用内存为代价实现多任务的并行。
Generator函数是ECMAScript 6对协程的实现但属于不完全实现只做到了暂停执行和转移执行权有一些特性没有实现比如不支持所调用的函数之中的yield语句。
Generator函数是ECMAScript 6对协程的实现但属于不完全实现只做到了暂停执行和转移执行权有一些特性没有实现比如不支持所调用的函数之中的yield语句即递归执行yield语句
如果将Generator函数看作多任务运行的方式存在多个进入点和退出点。那么一方面并发的多任务可以写成多个Generator函数另一方面继发的任务则可以按照发生顺序写在一个Generator函数之中然后用一个任务管理函数执行参考本节的“控制流管理”部分
@ -560,7 +562,7 @@ scheduler(longRunningTask());
function scheduler(task) {
setTimeout(function () {
if (!task.next().done) {
if (!task.next(task.value).done) {
scheduler(task);
}
}, 0);