Iterator&generator&await原理分析

280 阅读3分钟

1. 遍历器(Iterator)

1.1 基本概念

  • Iterator是一种机制(接口),并不是es6提供的一种标准类,为各种不同的数据结构提供统一的访问机制,任何数据结构之遥部署Iterator接口,就可以完成遍历操作,依次处理该数据结构的所有成员
    • 拥有next方法用于一次遍历数据结构的成员
    • 每一次遍历返回结果返回的结果是一个对象 {done: false, value: xxx}
      • done 记录是否遍历完成
      • value 当前遍历结果
class Iterator {
  constructor(arr) {
    this.arr = arr;
    this.index = 0;
  }
  next() {
    let index = this.index;
    let arr = this.arr;
    if (index > arr.length -1) {
      return {
        done: true,
        valur: undefined,
      };
    }
    return {
      done: false,
      valur: arr[this.index++],  // 先运算取值,后++
    };
  }
}

let arr = [10, 20, 30]
let itor = new Iterator(arr)

console.log(itor.next())  // {done: false, valur: 10}
console.log(itor.next())  // {done: false, valur: 20}
console.log(itor.next())  // {done: false, valur: 30}
console.log(itor.next())  // {done: true, valur: undefined}

1.2 内置Symbol.iterator属性

  • 只要拥有Symbol.iterator属性的数据结构(值),被称为可遍历的,可以基于for of循环处理

    • 数组,Array.prototype -> Symbol(Symbol.iterator)
    • 部分类数组:arguments/NodeList(节点集合)/HTMLCollection...
    • String
    • Set
    • Map
    • generator object
  • 对象默认不具备Symbol.iterator属性,属于不可被遍历的数据结构

  • 重构arr的遍历器

    • for of / 展开运算符 都走遍历器机制
let arr = [10, 20, 30];
arr[Symbol.iterator] = function() {
  // 返回一个符合iterator规范的对象,具备next方法
  let index = 0;
  let self = this;
  return {
    next() {
      console.log('OK')
      if (index > self.length -1) {
        return {
          done: true,
          value: undefined,
        };
      }
      let result = {
        done: false,
        value: self[index++],
      };
      return result
    }
  };
};
for (let item of arr) {
  console.log(item)
}
console.log(...arr)
  • 对象本身不是符合iterator遍历规范的数据结构
let obj = {
  0: 10,
  1: 20,
  2: 30,
  length: 3
};
for(let item of obj) {
  console.log(item)
}
// Uncaught TypeError: obj is not iterable
  • 让类数组对象可以遍历
let obj = {
  0: 10,
  1: 20,
  2: 30,
  length: 3,
  // [Symbol.iterator]:Array.prototype[Symbol.iterator]
  [Symbol.iterator]: function() {
    let index = 0;
    let self = this;
    return {
      next() {
        return index>self.length-1? {done: true, vaule: undefined} : {done: false, value: self[index++]}
      }
    }
  }
};
for(let item of obj) {
  console.log(item)
}
// 10 20 30
  • 让纯对象可以遍历

image.png

  • symbol唯一值,会遍历到自己写的iterator,无法排除,放到公有属性

image.png

2. 生成器对象(generator)

2.1 生成器函数基本用法

  • 生产器对象是由一个generator function返回的,并且它符合可迭代协议和迭代器(Iterator)协议

  • 加 * 生成器函数

function* func() {

}
func.prototype.AA = '10'
let iterator = func();

// 返回值是当前func的一个实例
// iterator.__proto__ === func.protorype
// console.log(iterator instanceof func) // true
// func 本身无法被new

console.log(iterator)

image.png

  • 用法
function* func() {
  console.log('A');
  yield 1;
  console.log('B');
  yield 2;
  console.log('C');
  yield 3;
  console.log('D');
}
let iterator = func();
console.log(iterator.next());  // 遇到一个yield就结束,再打印,从上一次yiled到下一个yield

image.png

2.2 next参数,给yield返回值赋值

function* func() {
  let x = yield 1;
  console.log(x);   // -> 10
}
let iterator = func();
iterator.next()   // {vaule: 1, done: false}
iterator.next()   // x是undefined {vaule: undefined, done: true}
如果 iterator.next(10) , yield返回值为10,赋给x,x打印10 

2.3 一个生成器中调用另一个生成器函数

function* func1() {
  yield 1;
  yield 2;
}
function* func2() {
  yield 3;
  yield* func1();
  yield 4;
}
let iterator = func2();
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

image.png

3 调用的写法

  • async+await就是generator+promise处理的语法糖

3.1 异步串行then调用写法

const func = x => {
  return new Promise(resolve => {
    setTimeout(() => {
      reslove(++x);   // ++x 先累加后操作
    }, 1000)
  })
}

// 异步串行写法,上一个返回值传给下一个
func(0).then(x => {
  console.log(x);  // 1
  return func(x);
}).then(x => {
  console.log(x);  // 2
  return func(x);
}).then(x => {
  console.log(x);  // 3
})

3.2 saync/await写法

(async function anonymous() {
  let x = await func(0);
  console.log(x)
  x = await func(x)
  console.log(x)
   x = await func(x)
  console.log(x)
})();

3.3 generator写法

function* generator(x) {
  x = yield func(x);
  console.log(x);   // 1
  
  x = yield func(x);
  console.log(x);  // 2
}

// 知道多少次,写死
let iterator = generator(0);
let result = iterator.next();  // 返回一个promise实例,{value: Promise, done: false}
result.value.then(x => {
  result = iterator.next(x);  // 第一次的结果作为值传递下去
  result.value.then(x => {
    result = iterator.next(x);
  })
});


// generator生成器函数,params初始执行generator传递的参数
function async(generator, ...params) {
  const iterator = generator(...params);
}

image.png

image.png