Iterable
实现了Iterable接口的数据结构就可以通过Iterator消费
Iterator暴露可迭代对象的api,无需了解他的数据结构
怎么实现Iterable接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Counter { constructor (limit ) { this .limit = limit } [Symbol .iterator ]() { let count = 1 ; let limit = this .limit return { next ( ) { if (count <= limit) return { done : false , value : count++ } else return { done : true , value : undefined } } return () { console .log ('提前终止...' ) return { done : true } } } } } let counter = new Counter (3 )for (let i of counter) { console .log (i) }
1 2 3 4 5 6 7 8 9 10 11 for (let i of counter) { console .log (i) if (i == 2 ) break }
迭代器如果没有关闭可以接着之前的位置继续。中断迭代器会调用return,但是调用了return不一定会关闭迭代器。例如Array类型
next()
next() 是迭代器的api
返回Iteratorresult对象, 包括 done和value
done: true | false 迭代完了吗
value: 当前取得
1 console .log (ita.next ());
内部实现了Iterable接口的类型
String
Array
Set
Map
arguments 对象
NodeList 等DOM集合类型
1 2 3 4 5 6 7 let arr = ['a' ,'b' ]let it = arr[Symbol .iterator ]console .log (it); let ita = arr[Symbol .iterator ]() console .log (ita);
自动兼容可迭代对象的
它们会自动调用工厂函数创建迭代器
for-of
数组解构 let [a, b] = [1,2]
扩展操作符 [1,2,3, ...arr2]
创建Set、Map
Promise.all()
Array.from()
yield*
伪数组没有迭代器,需要Array.from()转成数组
1 2 3 4 5 6 7 8 9 10 11 let fakerArr = { 0 : 'a' , 1 : 'b' , 2 : 'c' , } for ( let i in fakerArr){ console .log (fakerArr[i]) } for ( let item of fakerArr){ console .log (item) }
注意
迭代器会占用一个引用计数,组织垃圾回收可迭代对象
生成器 拥有在一个函数块内暂停 和恢复 代码执行的能力
生成器函数
1 function * generatorFn ( ){}
箭头函数不能声明为生成器函数
生成器对象
一开始处于suspended状态
实现了Iterator接口
next()
return() 必有
throw() 特有
注入一个错误,如果不用try-catch处理错误就会关闭生成器,处理了则跳过这次yield继续下去
1 2 3 4 5 6 7 8 9 10 11 12 function * generatorFn ( ) { console .log ('log...' ) return 'foo' } const g = generatorFn ()console .log (g);console .log (g.next ())
1 2 const g = generatorFn ();console .log (g === g[Symbol .iterator ]())
yield
yield 可以让生成器停止和开始执行
使用next()继续执行
yield 退出的生成器函数处于done: false状态
return() 出去的done: true
yield 只能在生成器函数内使用
1 2 3 4 5 6 7 8 9 10 11 function * generatorFn ( ) { yield 'a' yield 'b' return '0' } const g = generatorFn (); console .log (g.next ()) console .log (g.next ()) console .log (g.next ())
1 2 3 4 5 6 7 8 for (const x of generatorFn ()){ console .log (x) }
yield 实现输入输出
yield接收next里的参数,除了第一个next, 其作用是 启动生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 function * generatorFn (initial ) { console .log (initial); console .log (yield ); console .log (yield ); console .log (yield ); } const g = generatorFn ('initial' )g.next ('a' ) g.next ('b' ) g.next ('c' ) g.next ('d' )
yield同时输入输出
1 2 3 4 5 6 function * generatorFn ( ) { return yield 'foo' } const g = generatorFn ()console .log (g.next ()); console .log (g.next ('x00' ));
yield *增强yield行为,让他可以迭代一个可迭代对象
1 2 3 function * generatorFn ( ){ yield * [1 ,2 ,3 ] }
适合作默认迭代器
1 2 3 4 5 6 7 8 9 10 11 class Foo { constructor ( ){ this .value = [1 ,2 ,3 ] } * [Symbol .iterator ](){ yield * this .value } } for (let f of new Foo ()){ console .log (f) }
配合 Promise 实现异步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 function * readFileWithGen ( ) { try { const content1 = yield readFileWithPromise ('/etc/passwd' , 'utf8' ) console .log (content1) const content2 = yield readFileWithPromise ('/etc/profile' , 'utf8' ) console .log (content2) return 'done' } catch (err) { console .error (err) return 'fail' } } const run = generator => { return new Promise ((resolve, reject ) => { const g = generator () const next = res => { const result = g.next (res) if (result.done ) { return resolve (result.value ) } result.value .then ( next, err => reject (gen.throw (err).value ) ) } next () }) } run (readFileWithGen) .then (res => console .log (res)) .catch (err => console .log (err))
🔗async/await原理和co函数实现
实现async/await
async 会把函数变成Promise对象
async函数就是generator 函数,把 function* 替换成 async function ,把 yield 替换成 await
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const getFetch = (nums ) => new Promise ((resolve ) => { setTimeout (() => { resolve (nums + 1 ); }, 1000 ); }); function * gen ( ) { let res1 = yield getFetch (1 ); let res2 = yield getFetch (res1); let res3 = yield getFetch (res2); return res3; } function myAsync (gen ){ return ()=> new Promise ((resolve,reject )=> { let g = gen (); const next = (context )=>{ const {done, value} = g.next (context); if (done) resolve (value) else return Promise .resolve (value).then (val =>next (val)) } next (); }) }