tangyuxian
文章77
标签36
分类5
es6-Iterator,Generator和Async/Await的理解

es6-Iterator,Generator和Async/Await的理解

Iterator,Generator和Async/Await经常会被放在一起讨论,根据自己的理解做一个总结

一 Iterator

1 Iterator是遍历器,它是一种接口,作用如下:

  1. 为各种数据结构提供统一的接口访问;
  2. 数据结构的成员能够按某种次序排列;
  3. Iterator 接口主要供for...of消费

2 原生具备Iterator接口的数据结构如下:

  1. Array

  2. Map

  3. Set

  4. String

  5. TypedArray

  6. 函数的 arguments 对象

  7. NodeList 对象

它们有一个共同点,都具有Symbol.iterator属性

3 Symbol.iterator

对象的Symbol.iterator属性,指向该对象的默认遍历器方法;对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器.具体参照Symbol.iterator | MDN

为何必须实现它才可用for...of遍历?这是一个约定,迭代协议 | MDN

    let person = {}
    person[Symbol.iterator] = function() {
        let index = 1;
        return { 
            next() {
                return {done: index>10, value: index++} 
            }
        }
    }
    for (const item of person) {
        console.log(item)
    }

4 场景

  1. 解构赋值
  2. 扩展运算符
  3. yield*

二 Generator

Generator是一个可以暂停和继续执行的函数,所以它是状态机,封装了多个内部状态;

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

1 语法特点

  1. function关键字后面有一个星号
  2. 函数内部用 yield 关键字返回值

2 与 Iterator 接口的关系

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

function* gen(){
  // some code
}

var g = gen();

g[Symbol.iterator]() === g
// true

3 注意事项

function* count() {
  yield 1
  yield 2
  return 3
}
var c = count()
console.log(c.next()) // { value: 1, done: false }
console.log(c.next()) // { value: 2, done: false }
console.log(c.next()) // { value: 3, done: true }
console.log(c.next()) // { value: undefined, done: true }
function* count() {
  yield 1
  yield 2
  return 3
}
var c = count()
for (let i of c){
    console.log(i) // 1, 2
}

使用next()执行可以拿到return后的值,但是如果是通过for...of,将无法遍历到最后一个值;

另外for...of本身也在触发next(),当前的生成器都迭代完,for...of将不再触发,手动执行next()也将只会返回 { value: undefined, done: true }

三 Async/Await

Generator 函数的语法糖,函数语法特点是将 Generator 函数的星号(*)替换成async,将yield替换成await

1 特点

  1. 内置执行器:不需要调用next()方法,会自动执行函数内容,Generator如果想自动执行需要依赖co模块;
  2. 语义清晰:async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果;
  3. 适用性广泛:co模块约定yield命令后面只能是 Thunk 函数(指将多参数函数,其中入参中包含了callback函数变成单参数版本的函数)或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值,字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)
  4. 返回值是 Promise

更多特点参照阮一峰的async 函数 - ECMAScript 6入门

本文作者:tangyuxian
本文链接:https://www.tangyuxian.com/2022/07/25/%E5%89%8D%E7%AB%AF/es6/es6-Iterator-Generator%E5%92%8CAsync-Await%E7%9A%84%E7%90%86%E8%A7%A3/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可