一、基本概念
Generator函数是一种可以暂停执行,返回iterator对象的函数,yield是暂停标识
function* gen(){ yield 1; yield 2; }
Generator函数在function后面有一个*,内部有yield语句
function* gen(){ yield 1; yield 2; return '1' } let g = gen(); //调用Generator函数返回遍历器对象 console.log(g.next())//{"value":1,"done":false} console.log(g.next())//{"value":2,"done":false}
console.log(g.next())//{"value":"1","done":true}
console.log(g.next())//{"value":undefined,"done":true}
如果内部没有yield命令,generator函数和普通函数没有差别,只是暂停执行。
二、for of
generator函数返回遍历器对象,可以用for of遍历
function* gen(){ yield 1; yield 2; return '1' } for(let i of gen()){ console.log(i) }
//1
//2
三、next return throw
iterator对象都有这三个方法,但一般的内置默认的Symbol.iterator返回的对象没有return throw方法。
1.next方法可以向generator函数内部传递数据 yield命令本身没有返回值,next方法的参数可以用作yield的赋值。
function* gen(){ yield 1; let a = yield 2; console.log(a) //10 return a } let g = gen(); console.log(g.next())//{"value":1,"done":false} console.log(g.next()) //{"value":2,"done":false} 10 console.log(g.next(10)) //{"value":10,"done":false}
2.Generator函数返回的遍历器对象值,还有一个return
方法,可以返回给定的值,并且终结遍历Generator函数。
function* gen() { yield 1; yield 2; yield 3; } var g = gen(); g.next() // { value: 1, done: false } g.return("foo") // { value: "foo", done: true } 遍历结束 g.next() // { value: undefined, done: true }
3.Generator函数返回的遍历器对象,都有一个throw
方法,
a.可以在函数体外抛出错误,然后在Generator函数体内捕获。
b.内部抛出错误,而内部没有try catch捕获,外部可以捕获
c.generator函数内部抛出错误捕获了,不会阻止代码运行
var g = function* () { try { yield; } catch (e) { console.log('内部捕获', e); } }
var i = g(); i.next(); try { i.throw('a'); i.throw('b'); } catch (e) { console.log('外部捕获', e); }
//内部捕获 a
//外部捕获 b
第一个错误被Generator函数体内的catch
语句捕获,此时Generator函数就算执行完成了,不会再继续执行了。遍历器对象i
第二次抛出错误,由于Generator函数内部的catch
语句已经执行过了,不会再捕捉到这个错误了,所以这个错误就被抛出了Generator函数体,被函数体外的catch
语句捕获。
要注意遍历器对象的throw与全局的throw的区别 后者只能被函数体外的catch捕获。
四、yield*
yield* 后面是遍历器对象 可用于在generator函数内调用另一个generator函数 yield*相当于运用了for of
五、generator用于异步的同步表示
因为generator函数是可以暂停的,且yield是同步的,所有后一个yield肯定在上一个结束后才运行。
六、generator与协程
协城:可以交换执行权,达到“伪并行”的状态,其实在同一时间还是只有一个函数在运行
Generator函数是ECMAScript 6对协程的实现,但属于不完全实现。Generator函数被称为“半协程”(semi-coroutine),意思是只有Generator函数的调用者,才能将程序的执行权还给Generator函数。如果是完全执行的协程,任何函数都可以让暂停的协程继续执行。
七、generator的this
Generator函数总是返回一个遍历器,ES6规定这个遍历器是Generator函数的实例,也继承了Generator函数的prototype
对象上的方法。
function* g() { this.a = 11; } let obj = g(); obj.a // undefined
Generator函数返回的总是遍历器对象,而不是this
对象。所有obj拿不到a属性