初次邂逅
迭代器:具备遍历的功能; 一般可迭代对象具有Symbol.iterator属性 可迭代(可被遍历)的内置对象:数组(# Array.prototype[Symbol.iterator]()
)、字符串(String.prototype[Symbol.iterator]()
)等等;
let arr = [ 1 , 2 , 3 ]
for ( let item of arr) {
console. log ( item)
}
let str = 'lxx'
for ( let char of arr) {
console. log ( char)
}
自定义可遍历对象,具备Symbol.iterator属性
let obj = {
items : [ 6 , 7 , 8 ] ,
[ Symbol. iterator] ( ) {
let idx = 0 ;
let next = ( ) => {
if ( idx < this . items. length) {
return { value : this . items[ idx++ ] , done : false } ;
} else {
return { done : true } ;
}
} ;
return { next } ;
} ,
} ;
for ( let item of obj) {
console. log ( item) ;
}
生成器函数,有*
标识并且和关键字yield
搭配使用,可用来控制函数的执行,可暂停函数的执行
function * gen ( ) {
yield 1 ;
yield 2 ;
yield 3 ;
}
let it = gen ( )
console. log ( it)
调用生成器函数生成迭代器对象,具有next
、return
、throw
等方法 调用一次next
方法,就会执行一个yield
,有n
个yield
,则需要调用n + 1
个next
每调用一次next
时,执行的代码内容(范围)是上边的代码到yield
右侧(不包含左边的赋值)
let res1 = it. next ( ) ;
console. log ( res1) ;
let res2 = it. next ( ) ;
console. log ( res2) ;
let res3 = it. next ( ) ;
console. log ( res3) ;
let res4 = it. next ( ) ;
console. log ( res4) ;
除第一个调用的next
之外,后面调用时传递的参数,都会传(赋值)给相应位置的yield
左侧的变量
function * gen ( ) {
let r1 = yield 1 ;
console. log ( r1) ;
let r2 = yield 2 ;
console. log ( r2) ;
let r3 = yield 3 ;
console. log ( r3) ;
}
let it = gen ( )
it. next ( 'a' ) ;
it. next ( 'b' ) ;
it. next ( 'c' ) ;
it. next ( 'd' ) ;
因为生成器函数的执行结果是个迭代器对象,所以可以使用for...of
进行遍历,得到的每一项是yield
产生的值,有几个yield
就会循环几项
for ( let item of it) {
console. log ( item)
}
因为生成器函数中不确定有几个yield
(不确定有几个待执行的任务),但每执行完一个任务会知道是否所有任务已经完全执行完了,所以可以使用do...while
来执行
let res;
do {
res = it. next ( ) ;
console. log ( res. value) ;
} while ( ! res. done) ;
function next ( ) {
let { value, done } = it. next ( ) ;
if ( done) {
console. log ( 所有任务执行完毕") ;
} else {
console. log ( value) ;
next ( ) ;
}
}
next ( ) ;
function * gen ( ) {
yield 1 ;
yield new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
resolve ( 2 ) ;
} , 2000 ) ;
} ) ;
yield 3 ;
}
let it = gen ( ) ;
console. log ( it) ;
for ( let item of it) {
console. log ( item) ;
}
可以借助自定义迭代方法,检测出产生值的类型,进行特殊处理
function next ( ) {
let { value, done } = it. next ( ) ;
if ( done) {
console. log ( "函数执行完毕" ) ;
} else {
console. log ( value) ;
if ( value instanceof Promise ) {
value. then ( ( res ) => {
console. log ( res) ;
next ( ) ;
} ) ;
} else {
next ( ) ;
}
}
}
温故而知新
class PubSub {
constructor ( ) {
this . events = { } ;
}
on ( eventName, callback ) {
if ( this . events[ eventName] ) {
this . events[ eventName] . push ( callback) ;
} else {
this . events[ eventName] = [ callback] ;
}
}
emit ( eventName ) {
this . events[ eventName] . forEach ( ( callback ) => callback ( ) ) ;
}
}
function * tasks ( ) {
yield 111 ;
yield 222 ;
yield 333 ;
}
let it = tasks ( )
function next ( ) {
let { value, done} = it. next ( )
if ( done) {
console. log ( '所有任务执行完毕' )
} else {
console. log ( value)
next ( )
}
}
next ( )
有异步任务,同样希望按顺序执行,执行完上一个任务,才会执行下一个任务
function * tasks ( ) {
yield 111 ;
yield new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
resolve ( 222 ) ;
} , 2000 ) ;
} ) ;
yield 333 ;
}
let it = tasks ( ) ;
function next ( ) {
let { value, done } = it. next ( ) ;
if ( done) {
console. log ( "所有任务执行完毕" ) ;
} else if ( typeof value. then === "function" ) {
value. then ( ( res ) => {
console. log ( res) ;
next ( ) ;
} ) ;
} else {
console. log ( value) ;
next ( ) ;
}
}
next ( ) ;
< button id = " btn" > btn</ button>
< script>
btn. onclick = ( ) => {
pubSub. emit ( "send" ) ;
} ;
class PubSub {
constructor ( ) {
this . events = { } ;
}
on ( eventName, callback ) {
if ( this . events[ eventName] ) {
this . events[ eventName] . push ( callback) ;
} else {
this . events[ eventName] = [ callback] ;
}
}
emit ( eventName ) {
this . events[ eventName] . forEach ( ( callback ) => callback ( ) ) ;
}
}
let pubSub = new PubSub ( ) ;
function * tasks ( ) {
yield 111 ;
yield new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
resolve ( 222 ) ;
} , 2000 ) ;
} ) ;
yield 333 ;
yield "pause" ;
yield 444 ;
}
let it = tasks ( ) ;
function next ( ) {
let { value, done } = it. next ( ) ;
if ( done) {
console. log ( "所有任务执行完毕" ) ;
} else if ( value === "pause" ) {
pubSub. on ( "send" , ( ) => {
console. log ( "send事件触发了" ) ;
next ( ) ;
} ) ;
} else if ( typeof value. then === "function" ) {
value. then ( ( res ) => {
console. log ( res) ;
next ( ) ;
} ) ;
} else {
console. log ( value) ;
next ( ) ;
}
}
next ( ) ;
</ script>
嵌套的生成器函数,执行时,一层层进去,再一层层出来,最后执行完所有任务
function isCustomIterable ( obj ) {
if ( typeof obj[ Symbol. iterator] === "function" && typeof obj !== "string" ) {
const iterator = obj[ Symbol. iterator] ( ) ;
if ( typeof iterator. next === "function" ) {
if ( ! Array. isArray ( obj) ) {
return true ;
}
}
}
return false ;
}
function * task2 ( ) {
yield "任务二开始" ;
yield new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
resolve ( "任务三:异步任务" ) ;
} , 2000 ) ;
} ) ;
yield "任务二结束" ;
}
function * task1 ( ) {
yield "任务一开始" ;
yield task2 ( ) ;
yield "任务一结束" ;
}
function * tasks ( ) {
yield "总任务开始" ;
yield task1 ( ) ;
yield "总任务结束" ;
}
function run ( generator, cb ) {
const it = typeof generator === "function" ? generator ( ) : generator;
function myNext ( ) {
const { value, done } = it. next ( ) ;
if ( done) {
console. log ( "当前任务所有步骤都完成" ) ;
cb && cb ( ) ;
} else if ( isCustomIterable ( value) ) {
run ( value, myNext) ;
} else if ( value instanceof Promise && typeof value. then === "function" ) {
value. then ( ( res ) => {
console. log ( res) ;
myNext ( ) ;
} ) ;
} else {
console. log ( value) ;
myNext ( ) ;
}
}
myNext ( ) ;
}
run ( tasks) ;
再见来不及挥手
迭代器对象具有可被遍历的特性 生成器函数可产生迭代器对象 生成器函数里面的代码可被控制执行 生成器函数中有n
个yield
,那么需要调用n+1
次next
方法,生成器函数才会执行完