主要想了解的是async函数,但牵扯太多,环环相扣,挨个说叭

Iterator

概念

遍历器是一种机制:可以遍历处理各种数据结构(Array,Set,Map等)。也可理解是一种接口:为各种不同数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
作用:

  • 为各种数据结构提供 统一、简便的访问接口
  • 使数据结构的成员能够按照某种次序排列
  • 创建了 for…of 循环

理解遍历器的执行过程

  1. var it = makeIterator(['a','b'])
  2. it.next() // { value: "a", done: false}
  3. it.next() // { value: "b", done: false}
  4. it.next() // { value: undefined, done: true}
  5. function makeIterator(array) {
  6. var nextIndex = 0;
  7. return {
  8. next : function(){
  9. return nextIndex < array.length ?
  10. {value: array[nextIndex++], done: false} :
  11. {value: undefined, done: true};
  12. }
  13. }
  14. }
  1. 创建一个指针对象,指向当前数据结构的起始位置,指针对象必返回next方法。第一次调用指针对象的next方法,指针指向数据结构的第一个成员。第二次调用next方法,指针指向数据结构的第二个成员。不断调用指针对象的next方法,直到指向数据结构的结束位置。
  2. 每一次调用next方法都会返回,数据结构当前的成员信息。value和done属性组成的对象:{ value : ‘xx’, done : false }

    「可遍历的」

  3. “可遍历的”指一种数据部署了interator接口,可直接使用for…of… 循环。

  4. 默认的Iterator部署在数据结构的Symbol.interator属性上。所以说,一个数据结构只要部署了Symbol.interator属性,就认为是「可遍历的」。
    1. Symbol.interator是一个表达式,要放在方括号内才有效:[Symbol.interator],返回Symbol对象的iterator属性。
    2. 其本身是个函数,可理解为当前数据结构默认的遍历器生成函数,执行这个函数返回一个遍历器。

      默认Iterator

      有些数据结构原生具备Interator接口,即有Symbol.interator属性,可被for…of… 循环遍历
  • 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 }

  1. <a name="e7MQz"></a>
  2. #### 使用场景
  3. 结构赋值 、 扩展运算符、yield*、for...of... 、Array.from() 、Map()、Set()、Promise.all()、Promise.race()
  4. <a name="uBjAo"></a>
  5. # Generator
  6. <a name="orD9V"></a>
  7. #### 概念
  8. **Generator函数 **ES6提供的 一种解决异步编程解决方案。可理解为是一个状态机,封装了多个内部状态。也是一个遍历器对象生成函数,会返回一个新的遍历器对象。
  9. ```javascript
  10. function* helloWorldGenerator() {
  11. yield 'hello';
  12. yield 'world';
  13. return 'ending';
  14. }
  15. var hw = helloWorldGenerator();
  1. Generator函数,function 关键字和函数名之间有一个星号*
  2. 函数体内部用yield表达式,来定义不同的内部状态。
  3. 调用Generator函数后,该函数并不会执行。如上函数的执行结果hw,是一个指向内部状态的指针对象,即遍历器对象
  1. console.log(hw.next())
  2. console.log(hw.next())
  3. console.log(hw.next())
  4. console.log(hw.next())

image.png
调用 next() 方法,Generator函数开始执行。遇到第一个yield表达式,停止,返回当前yield表达式的值,以及是否结束的状态done。再调 next(), 再接着执行,再到下一个yield表达式,或return。

yield表达式

由于Generator函数返回的是遍历器对象,调用 next() 才会获得下一个内部状态,所以可理解为 yield表达式是暂停标志。
调用 next() 后的执行逻辑:

  1. 遇到yield表达式,就暂停后续操作。并将紧跟在yield后的表达式的值当作返回对象的value值。
  2. 下一次再调用 next() 方法时,继续往下执行,直到遇到下一个yield表达式。
  3. 如果没有遇到新的yield表达式,就一直运行到函数结束,直到 return 语句为止,并将return后的值当作返回对象的value值。
  4. 如果该函数没有 return语句,则返回对象的value值为undefined。

1、暂缓执行函数
yield表达式的值不会立即求值,只会在next方法将指针移到这一步才执行。
2、yield表达式只能用在Generator函数里面
用在普通股函数内会报错
3、yield表达式如果用在另一个表达式之中,必须放在圆括号里面。

  1. function* demo() {
  2. console.log('Hello' + (yield)); // OK
  3. console.log('Hello' + (yield 123)); // OK
  4. }

next()参数

yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
它的重要意义在于,Generator函数从暂停状态到开始运行,它的上下文状态是不变的,那通过next参数,就可以在Generator函数开始运行之后,继续向函数传进新的值,从而调整函数的值。

  1. function* testNext(x){
  2. const y = yield x+6;
  3. const z = yield y*2;
  4. return (x+y+z)
  5. }
  6. const req = testNext(4)
  7. console.log(req.next())
  8. console.log(req.next(2))
  9. console.log(req.next(2))

image.png

与Interator接口的关系

1、由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.interator属性,从而使得该对象具有 Iterator 接口。

  1. var myIterable = {};
  2. myIterable[Symbol.iterator] = function* () {
  3. yield 1;
  4. yield 2;
  5. yield 3;
  6. };
  7. [...myIterable] // [1, 2, 3]

2、Generator 函数执行后,返回一个遍历器对象。该对象本身也具有Symbol.interator属性,执行后返回自身。

  1. function* gen(){
  2. }
  3. var g = gen();
  4. g[Symbol.iterator]() === g

3、for…of…
for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。

  1. function* foo() {
  2. yield 1;
  3. yield 2;
  4. yield 3;
  5. yield 4;
  6. yield 5;
  7. return 6;
  8. }
  9. for (let v of foo()) {
  10. console.log(v);
  11. }
  12. // 1 2 3 4 5

一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for…of循环之中。

  1. function* numbers () {
  2. yield 1
  3. yield 2
  4. return 3
  5. yield 4
  6. }
  7. // 扩展运算符
  8. [...numbers()] // [1, 2]
  9. // Array.from 方法
  10. Array.from(numbers()) // [1, 2]
  11. // 解构赋值
  12. let [x, y] = numbers();
  13. x // 1
  14. y // 2
  15. // for...of 循环
  16. for (let n of numbers()) {
  17. console.log(n)
  18. }
  19. // 1
  20. // 2

throw() 、return()、和next()

…待续

应用

1. 部署Iterator接口

利用Generator接口,可以为任何对象部署Iterator接口

  1. function* objectEntries() {
  2. let propKeys = Object.keys(this);
  3. for (let propKey of propKeys) {
  4. yield [propKey, this[propKey]];
  5. }
  6. }
  7. let jane = { first: 'Jane', last: 'Doe' };
  8. jane[Symbol.iterator] = objectEntries;
  9. for (let [key, value] of jane) {
  10. console.log(`${key}: ${value}`);
  11. }

Async