主要想了解的是async函数,但牵扯太多,环环相扣,挨个说叭
Iterator
概念
遍历器是一种机制:可以遍历处理各种数据结构(Array,Set,Map等)。也可理解是一种接口:为各种不同数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
作用:
- 为各种数据结构提供 统一、简便的访问接口
- 使数据结构的成员能够按照某种次序排列
- 创建了 for…of 循环
理解遍历器的执行过程
var it = makeIterator(['a','b'])
it.next() // { value: "a", done: false}
it.next() // { value: "b", done: false}
it.next() // { value: undefined, done: true}
function makeIterator(array) {
var nextIndex = 0;
return {
next : function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
}
}
- 创建一个指针对象,指向当前数据结构的起始位置,指针对象必返回next方法。第一次调用指针对象的next方法,指针指向数据结构的第一个成员。第二次调用next方法,指针指向数据结构的第二个成员。不断调用指针对象的next方法,直到指向数据结构的结束位置。
每一次调用next方法都会返回,数据结构当前的成员信息。value和done属性组成的对象:{ value : ‘xx’, done : false }
「可遍历的」
“可遍历的”指一种数据部署了interator接口,可直接使用for…of… 循环。
- 默认的Iterator部署在数据结构的Symbol.interator属性上。所以说,一个数据结构只要部署了Symbol.interator属性,就认为是「可遍历的」。
- Array
- Map
- Set
- String
- TypedArray
- 函数的arguments对象
- NodeList对象 ```javascript let arr = [‘a’, ‘b’, ‘c’]; let iter = arrSymbol.iterator; //⚠注意:此处属性后要加()
iter.next() // { value: ‘a’, done: false } iter.next() // { value: ‘b’, done: false } iter.next() // { value: ‘c’, done: false } iter.next() // { value: undefined, done: true }
<a name="e7MQz"></a>
#### 使用场景
结构赋值 、 扩展运算符、yield*、for...of... 、Array.from() 、Map()、Set()、Promise.all()、Promise.race()
<a name="uBjAo"></a>
# Generator
<a name="orD9V"></a>
#### 概念
**Generator函数 **ES6提供的 一种解决异步编程解决方案。可理解为是一个状态机,封装了多个内部状态。也是一个遍历器对象生成函数,会返回一个新的遍历器对象。
```javascript
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
- Generator函数,function 关键字和函数名之间有一个星号*
- 函数体内部用yield表达式,来定义不同的内部状态。
- 调用Generator函数后,该函数并不会执行。如上函数的执行结果hw,是一个指向内部状态的指针对象,即遍历器对象
console.log(hw.next())
console.log(hw.next())
console.log(hw.next())
console.log(hw.next())
调用 next() 方法,Generator函数开始执行。遇到第一个yield表达式,停止,返回当前yield表达式的值,以及是否结束的状态done。再调 next(), 再接着执行,再到下一个yield表达式,或return。
yield表达式
由于Generator函数返回的是遍历器对象,调用 next() 才会获得下一个内部状态,所以可理解为 yield表达式是暂停标志。
调用 next() 后的执行逻辑:
- 遇到yield表达式,就暂停后续操作。并将紧跟在yield后的表达式的值当作返回对象的value值。
- 下一次再调用 next() 方法时,继续往下执行,直到遇到下一个yield表达式。
- 如果没有遇到新的yield表达式,就一直运行到函数结束,直到 return 语句为止,并将return后的值当作返回对象的value值。
- 如果该函数没有 return语句,则返回对象的value值为undefined。
1、暂缓执行函数
yield表达式的值不会立即求值,只会在next方法将指针移到这一步才执行。
2、yield表达式只能用在Generator函数里面
用在普通股函数内会报错
3、yield表达式如果用在另一个表达式之中,必须放在圆括号里面。
function* demo() {
console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
}
next()参数
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
它的重要意义在于,Generator函数从暂停状态到开始运行,它的上下文状态是不变的,那通过next参数,就可以在Generator函数开始运行之后,继续向函数传进新的值,从而调整函数的值。
function* testNext(x){
const y = yield x+6;
const z = yield y*2;
return (x+y+z)
}
const req = testNext(4)
console.log(req.next())
console.log(req.next(2))
console.log(req.next(2))
与Interator接口的关系
1、由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.interator属性,从而使得该对象具有 Iterator 接口。
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
2、Generator 函数执行后,返回一个遍历器对象。该对象本身也具有Symbol.interator属性,执行后返回自身。
function* gen(){
}
var g = gen();
g[Symbol.iterator]() === g
3、for…of…
for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for…of循环之中。
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
// 扩展运算符
[...numbers()] // [1, 2]
// Array.from 方法
Array.from(numbers()) // [1, 2]
// 解构赋值
let [x, y] = numbers();
x // 1
y // 2
// for...of 循环
for (let n of numbers()) {
console.log(n)
}
// 1
// 2
throw() 、return()、和next()
应用
1. 部署Iterator接口
利用Generator接口,可以为任何对象部署Iterator接口
function* objectEntries() {
let propKeys = Object.keys(this);
for (let propKey of propKeys) {
yield [propKey, this[propKey]];
}
}
let jane = { first: 'Jane', last: 'Doe' };
jane[Symbol.iterator] = objectEntries;
for (let [key, value] of jane) {
console.log(`${key}: ${value}`);
}