Generator 是一个分步执行的函数,可以根据需要执行下一步。合理利用这个特性可以很好解决异步编程回调嵌套的问题。
简介
Generator很像是一个函数,但是你可以暂停它的执行。你可以向它请求一个值,于是它为你提供了一个值,但是余下的函数不会自动向下执行直到你再次向它请求一个值。
特征
function后面跟*,函数体内有yield关键字- 执行Genertor函数返回一个遍历器对象,遇到
yield暂停执行,调用next继续执行 next方法返回的对象中value表示当前指针对应的yield语句的返回值,done表示遍历是否结束- 当遍历结束之后,重复调用都只会返回
{value: undefined, done: true} - 如果函数有
return,则返回return后面表达式的值做为value的值,如果没有,则返回undefined做为value的值
function* fn1(){ |
多维数组扁平化
var arr = [1, [[2, 3], 4], [5, 6]]; |
Iterator接口
任意一个对象的 Symbol.iterator 方法,等于该对象的遍历器生成函数
将 Generator 函数赋值给对象的 Symbol.iterator 属性,可使对象具有Iterator接口
具有Iterator接口的对象可使用 ... 延展符展开
var k = {}; |
Generator 函数返回的遍历器对象也有Symbol.iterator对象,执行后返回自身
var m = function* (){} |
yield 语句本身没有返回值,或者永远返回 undefinednext 方法有参数时,参数将会被当然上一个 yield 语句的返回值
function* f() { |
Generator函数在运行时,内部的 上下文(context )是保持不变的,但可以通过 next 方法不但的向函数体注入参数,从而改变函数的行为。next 方法第一次调用时的参数会被忽略,只有后面的传参会被使用,第一个next方法可视作是启动遍历器对象
function* foo(x) { |
for...of 遍历
可以使用 for...of 遍历Generator 对象,不需要调用 next
function* fn(){ |
由于 for...of 遍历时,当返回的对象 done 为 true 时就终止了循环,且不返回对象的 value, 所以最后的 4 没有输出,执行到 return 返回的是 {value: 4, done: true}
例1:利用Generator函数和for…of循环,实现斐波那契数列
function* fibonacci(){ |
例2:给原生对象添加Iterator遍历接口
function* objectEntries(){ |
for...of循环 / 扩展运算符... / 解构赋值 / Array.from 都可以操作Generator函数返回的Iterator对象
function* numbers(){ |
Generator.prototype.throw
Generator函数内部部署 try...catch 可以对多个 yield 语句进行错误捕捉
Generator函数内部抛出错误可以被函数体外catch捕获
Generator函数体外抛出错误可以被函数体内catch捕获
function* fnA(){ |
如果Generator函数返回的Iterator对象在外部抛出了错误,而函数体内部又没有捕获,那么这个错误将抛给全局,程序中断
var gen = function* gen(){ |
Generator函数返回的Iterator对象throw一个错误后,会同时调用一次next方法
var gen = function* gen(){ |
Generator.prototype.return
遍历器对象调用return可以改变返回的结果的vaule,并结束遍历返回的done为true
如果Generator函数内部有try…finally代码块,那么return方法会推迟到finally代码块执行完再执行function* numbers () {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var g = numbers()
g.next() // { done: false, value: 1 }
g.next() // { done: false, value: 2 }
g.return(7) // { done: false, value: 4 }
g.next() // { done: false, value: 5 }
g.next() // { done: true, value: 7 }
yield*
用于在一个Generator函数里面执行另一个Generator函数
function* fn1(){ |
yield* 在Generator函数中可以遍历任何具有Iterator接口的对象
function* fn4(){ |
yield 后面的Generator函数中可以通过 return 返回数据给 yield 所在的Generator函数
function* fn5(){ |
多维数组转一维数组function* flatArr(arr){
if(Array.isArray(arr)){
for(var k = 0; k<arr.length; k++){
yield* flatArr(arr[k])
}
}else{
yield arr;
}
}
var arr1 = [1,[2,3,[4,5,6]],7,[8,9]]
for(var i of flatArr(arr1)){
console.log(i)
}
// 1,2,3,4,5,6,7,8,9
二叉树遍历
function Tree(left, label, right){ |
做为对象属性
var obj = { |
状态保持function* tick(){
while(true){
yield 'Tick'
yield 'Tock'
}
}
var t = tick();
t.next();
t.next();
t.next();
t.next();
应用场景
异步操作同步化
使用嵌套回调
function asyncFn1(done){ |
使用Generator封装,可以简化回调,让异步写起来更像是同步
//使用done回调保证任务按顺序执行 |
任务流程管理
依次执行数组中的步骤
var step1 = () => 1; |
将多个步骤组合成多个任务,并依次执行这多个任务
var step1 = () => 1; |
部署Iterator接口
给任意对象部署Iterator接口
function* iterEntries(obj) { |
作为类数据结构
function doStuff(){ |