Iterator
概念
iterator遍历器,为了给js中多种的数据结构(原来的Array,String和ES6的Set,Map)加一个统一简单的调用,加上了一个Iterator接口,可以统一使用for...of
来按一定顺序遍历数据结构。【嗯,还有扩展运算符...
】
ES6为以下一些结构实现了iterator接口
- Array
- String
- Set
- Map
- arguments
- NodeList
【注意没有Object,因为Object结构遍历的顺序是由开发者定义的,想要使用遍历器的语法,可以自行实现遍历器接口】
实现遍历器接口
所有数据结构有属性名为
Symbol.iterator
,值为一个返回拥有next属性的对象(遍历器对象)的函数即可,next函数一般就返回一个拥有done和value两个属性对象,value的值就是遍历的值,done为布尔值表示能(false)否(true)继续遍历;next函数每被调用一次就往下一个遍历值移动【接口
Symbol.iterator
,其实是一个Symbol值,因而可以作为一个对象的属性名】示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24var obj = {
a:'first',
b:'second',
c:'third',
d:'fourth'
}
obj[Symbol.iterator]=function(){
let ary = ['a','b','c','d']
const self = this
let index = 0
// 返回遍历器对象
return {
// 遍历器对象的next属性
next:function(){
return index<ary.length?
{value:self[ary[index++]],done:false} :
{value:undefined,done:true}
}
}
}
for(let val of obj){
console.log(val) // first second third fourth
}
Generator
概念
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
Generator函数的写法是,
function *generatorDemo(){ ... yield val1; ... yield val2; ... return val3}
函数名前关键字function后加*号,函数体使用yield关键字它内部逻辑是,调用函数,然后返回一个iterator遍历器对象(对象,带属性next,next为函数),不执行函数代码;然后每次调用遍历器对象的next方法就会执行代码到定义时Generator函数体yield关键字后表达式,并返回yield后表达式的值作为next返回对象value属性的值;这样多次,直到最后的return。
普通使用例子
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
29function *generatorDemo(){
console.log(1)
yield 'hello'
console.log(2)
yield 'generator'
console.log(3)
return 'done'
}
var gd = generatorDemo()
console.log('------------')
console.log(gd.next())
console.log('------------')
console.log(gd.next())
console.log('------------')
console.log(gd.next())
console.log('------------')
console.log(gd.next())
// ------------
// 1
// {value:hello,done:false}
// ------------
// 2
// {value:generator,done:false}
// ------------
// 3
// {value:done,done:false}
// ------------
// {value:undefined,done:true}
yield返回值
yield 也可以返回值,外部传值到Generator函数内部;比较值得注意的时传值的时机。
1 | function *f(){ |
yield*
Generator嵌套,yield* 语法。因为当yied 后表达式也是一个Generator时可以使用yield*把后面的表达式的next给“暴露”出去调用;
【所有实现了Iterator接口的数据结构都可以被yield*解析处理(yield不行)】
【yield* 只能处理遍历器对象,单纯的数字这些会报错】
【yield* 可以接收返回值,当表达式是Generator函数调用并这个函数有return语句】
1 | // 需求:for of遍历两个生成器函数A,B,期望按序先遍历了一个生成器A的再遍历另外一个B的 |
应用
延迟调用:从普通使用例子可以知道,不执行next,代码是不会被执行的,所以当没有使用yield时,只有return,那么只有调用一次next时函数才会被执行
1
2
3
4
5
6
7
8
9
10function *delayRun(){
console.log('run')
return
}
var tmp = delayRun()
console.log('------------')
console.log(tmp.next())
// ------------
// run
// {value:undefined,done:true}因为Generator返回的就是遍历器,而Iterator接口函数要的也是一个返回遍历器的函数,那么可以使用Generator函数来简化Iterator接口的编写,按照期望的顺序来写yield 表达式即可(妙啊)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var obj = {
a:'first',
b:'second',
c:'third',
d:'fourth'
}
obj[Symbol.iterator] = function *(){
yield this.a
yield this.b
yield this.c
// 这里不能写return,for...of语法是不会识别到return的,因为return返回的done为true了,不会被for...of遍历
yield this.d
}
for(let val of obj){
console.log(val) // first second third fourth
}
async/await
概念
直接看使用例子,不阻塞的情况下,使用同步代码实现异步调用的;
1 | // 正常promise调用 |
这里的重点是如何理解“同步代码实现异步调用”,async函数是异步的,每个await都会完成异步任务后才执行后面的代码。
和promise一样的时机调用,但语法上比promise阅读流畅很多。
原理
async/await可以说是Generator的一个语法糖,它的原理就是使用Generator实现的
1 |
|
参考
Iterator 和 for…of 循环 - ECMAScript 6入门
Generator 函数的语法 - ECMAScript 6入门
最后更新: 2021年08月07日 16:17
原始链接: https://idkhts.github.io/2021/08/07/ES6-Iterator%E3%80%81Gengerator%E3%80%81Async-Await/