须要Promise源码版的朋友:传送连接html
本文主要讲述(iterator)和生成器*/yield
之间的联系和各自的用法,以及生成器的高配版本aysnc/await
的使用。数组
大纲:promise
- 迭代器(iterator)
- 生成器
*/yield
- 异步版生成器
aysnc/await
迭代器(iterator)
先瞅瞅“迭代”,这个词是什么意思呢?每一次“过程”的重复,称之为迭代。不过迭代是会保留结果的,也就说每次都是以上一次迭代的结果为基准,开始下一次的迭代。举个例子,迭代这个词常常出如今产品开发之中,每一个周期都会有产品的迭代开发,可是不可能每次都是从零开始作产品,确定是基于上一版本的产品进行开发,也就是进行迭代。异步
从中咱们能够整理出关于迭代的两个关键点:async
- 过程是重复的
- 返回上一次的迭代结果
那么JS中的“迭代器”是个怎样的概念呢?this
查看MDN中的概念:传送地址url
我的观点:JS中的迭代器,就是一个数组对象,不断地调用
next
重复获取过程,而后每次都返回一个结果。等到没有东西可返回了,就终止。所以next
的返回对象有两个属性done
和value
。done
表示是否结束了,value
表示当前迭代的结果。当done
为true
的时候,表示迭代已结束,这时候是没有返回结果的也就是没有value
这个属性。spa
然而迭代器是有一系列的规范的:.net
查看MDN中的概念:传送地址code
迭代器
- 关于迭代器,就是咱们上面讨论的
next
方法,返回done
和value
(done:true
时能够省略)两个参数。
function iteratorFunc(){ let arr=[...arguments] let nIndex=0 return { next:()=>{ return nIndex<arr.length? {value:arr[nIndex++],done:false}:{done:true} } } } let a=iteratorFunc(1,2,3) console.log(a.next())//{done:false,value:1} console.log(a.next())//{done:false,value:2} console.log(a.next())//{done:false,value:3} console.log(a.next())//{done:true}
可迭代“对象”
- 关于可迭代“对象”,咱们须要再对象上实现
@@iterator
方法,也就是[Symbol.iterator]
,返回一个自定义的迭代方法,以代表这个对象是能够迭代的。有些JS内置的对象就是可迭代的,好比String,Array。
自带的可迭代事例:
let str="我是欢乐的迭代器" let b=str[Symbol.iterator]() console.log(b.next())//{value: "我", done: false} console.log(b.next())//{value: "是", done: false} console.log(b.next())//{value: "欢", done: false}
有没有很神奇啊!用了这么久的字符串,竟然还有这种操做。他的效果等同于上方的自定义迭代方法。那么咱们来写个自定义的迭代方法:
str[Symbol.iterator] = function() { return { // this is the iterator object, returning a single element, the string "bye" next: function() { this._index += 2 if (this._index<str.length) { return { value: str[this._index], done: false }; } else { return { done: true }; } }, _index:-2 }; }; let c=str[Symbol.iterator]() console.log(c.next())//{value: "我", done: false} console.log(c.next())//{value: "欢", done: false} console.log(c.next())//{value: "的", done: false} console.log(c.next())//{value: "代", done: false} console.log(c.next())//{done: true}
这里我写的迭代器是返回一个隔一个字符。运行成功~yeah~
生成器(generator)
感受写迭代器仍是很绕呢,因而出现了生成器(generator),专门帮咱们生成迭代器的存在。
function * g(){} let it= g() console.log(it.next())//{value: undefined, done: true}
看到熟悉的结构没有!{value: undefined, done: true}
,不过咱们没有值。这个时候要向你们推荐*
的好基友yield
,一个yield
对应一个next
的值。
咱们改写下上方的字符串的迭代器:
str[Symbol.iterator]= function * (){ let index=-2; while(index<this.length){ index += 2 yield this[index] } } let kk=str[Symbol.iterator]() console.log(kk.next())//{value: "我", done: false} console.log(kk.next())//{value: "欢", done: false} console.log(kk.next())//{value: "的", done: false} console.log(kk.next())//{value: "代", done: false}
是否是方便了不少。
咱们带着几个疑问来看看生成器:
yield
的返回值是啥?- 执行顺序?
实例代码:
function * gy(){ console.log("zero") let fisrt=yield "first" console.log("fisrt",fisrt) let second=yield "first" console.log("second",second) } let ity= gy()
第一次执行ity.next()
,只打印了zero
第二次执行ity.next()
,只打印了first undefined
第三次执行ity.next("third")
,只打印了second third
因而可知每次的next都止步于yield
,就再也不执行下去了。yield
每次返回的都是当前ity.next(value)
的value
值。
aysnc/await
咱们来看看对于Promise这个对象的迭代器,咱们该怎么处理。也就是每一个迭代器都是异步的。
function setTime(value,id){ return new Promise((r,j)=>setTimeout(() => { console.log(value) r(id) }, 10)) } function *a(){ let r1 = yield setTime("first",1) console.log(r1) let r2 =yield setTime("second",2) console.log(r2) let r3 =yield setTime("third",3) console.log(r3) } let k=a(); new Promise((resolve,reject)=>{ function next(data){ let {value,done}=k.next(data) //k.next()返回一个promise,所以能够then if(!done){ value.then((data)=>{ console.log(data) next(data) }) } } next(); })
由于每一个都是异步的,因此须要咱们二次处理,这个时候aysnc/await
就能够出场了。只须要把*/yield无缝改为aysnc/await便可。
async function a() { let r1 = await setTime("first",1) console.log(r1) let r2 = await setTime("second",2) console.log(r2) let r3 = await setTime("third",3) console.log(r3) } a()