前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端Tips#6 - 在 async iterator 上使用 for-await-of 语法糖

前端Tips#6 - 在 async iterator 上使用 for-await-of 语法糖

作者头像
JSCON简时空
修改2020-03-20 10:49:41
5890
修改2020-03-20 10:49:41
举报
文章被收录于专栏:JSCON简时空JSCON简时空

A. 视频讲解

前往 前端Tips#6 视频讲解

B. 文字讲解

1、场景简述

以下代码中的 for...of 操作,打印顺序 "2、3、4"(总共耗费时间 4s):

代码语言:txt
复制
const delay = (time) => () => setTimeout(() => { console.log(time) }, time * 1000);

const delays = [delay(3), delay(2), delay(4)];

for (cur of delays) {
    cur();
}

但我们想要以数组顺序打印 “3、2、4”(总共耗时9s),请问该如何实现?

2、同步迭代器

以常见的数组打印为例,下述代码会依次打印出 "0、1":

代码语言:txt
复制
for(const cur of [0, 1]){
    console.log(cur);
}

那么如何用 同步迭代器 实现上述同等输出?

Iterator 是 ECMAScript 2015 引进的功能,它就是一个 function,只不过对这个 function 的形式有特殊的规定:

  1. 返回对象必须包含 next 属性,该属性也是 function
  2. next 函数返回值必须返回包含 donevalue 这两个字段的对象

有了 Iterator,就可以借助 [Symbol.iterator] 构造出 可迭代对象(Iteratable)

代码语言:txt
复制
// 返回一个可迭代对象,注意 [Symbol.iterator] 这个 key
const someIteratable = {
    [Symbol.iterator]: someIterator
}

凡是可迭代对象就可以使用 for...of 语法,所以这是一种层层迭进的关系。

3、使用迭代器实现数组打印

知道了迭代器的概念后,就可以借助迭代器实现上述的数组打印功能,首先自定义构造出 countIterator 迭代器

代码语言:txt
复制
let count = 0;
function countIterator() {
    // 返回一个迭代器对象,对象的属性是一个 next 方法
    return {
        next: function () {
            if (count < 2) {
                // 当没有到达末尾时,返回当前值,并把索引加1
                return { value: count++, done: false };
            }

            // 到达末尾,done 属性为 true
            return { value: count, done: true };
        }
    };
}

然后创建出可迭代对象,由于该对象的行为和 [0,1] 这个数组类似,所以起名为 customArray

代码语言:txt
复制
// 返回一个可迭代对象,注意 [Symbol.iterator] 这个 key
const customArray = {
    [Symbol.iterator]: countIterator
}

最后给这个可迭代对象应用 for...of 即可,就能打印出 0、1 内容:

代码语言:txt
复制
for (const cur of customArray) {
    console.log(cur)
}

通过这个例子你就应该比较容易迭代器的理解,其实 JS 原生的StringArrayMapSet 等都是可迭代对象,因为它们的原型对象都有一个 Symbol.iterator 方法

4、异步迭代器

理解了同步迭代器,那么 异步迭代器(Async Iterator)也就很容易理解了,它和同步迭代器的差别在于:

  1. 异步迭代器必须返回 Promise 对象,且该 Promise 返回 { value, done } 格式对象
  2. 异步可迭代对象(Async Iteratable)用 Symbol.asyncIterator 作为 key
  3. 异步可迭代对象(Async Iteratable)可用 for-await-of 进行迭代

Async iterator 是 ECMAScript 2018 引进的

借助异步迭代器就可以实现本期开头所讲的功能,实现自定义的 delayIteraterable 可迭代对象,它使用 [Symbol.asyncIterator] 作为 key,其 value 就是异步迭代器:

代码语言:txt
复制
const promisify = func => (...args) =>
    new Promise((resolve, reject) =>
        func(...args, (err, result) => (err ? reject(err) : resolve(result)))
    );

const delayIteraterable = {
    [Symbol.asyncIterator]: () => {
        return {
            next: () => {
                const cur = promisify(delays.shift());
                return cur().then(res => {
                    return {
                        done: delays.length === 0,
                        value: res
                    }
                });
            }
        }
    }
}

这里用到的 promisify 函数,具体可参考前端 Tips - 第 5 期的内容讲解。

然后直接搭配 for-await-of 语法糖使用,就能进行异步迭代,按我们的要求依次输出 “3、2、4”(总共耗时9s)

代码语言:txt
复制
const execIt = async function () {
    for await (const cur of delayIteraterable) {
        console.log(cur);
    }
}
execIt();

5、扩展:Generator & Async Generator

除了用迭代器生成 可迭代对象 外,还能用 Generator(生成器)生成 可迭代对象,而且一般来讲代码实现也更为紧凑。

由于时间关系就不展开了,感兴趣的可阅读文末的参考文章自行学习。本期的例子也提供了 generator 的版本可供参考,链接:https://github.com/boycgit/fe-program-tips/blob/master/src/6-async-iterator/async-yield.js

6、参考文档

  • for await...of:官方 for await...of 教程
  • Asynchronous Iterators in JavaScript:通俗易懂的教程,条理清晰
  • ES2018 新特征之:异步迭代器 for-await-of:ES 2018 系列教程中的异步迭代器教程
  • map for async iterators in JavaScript:Youtube 上的教程,使用异步迭代器完成异步 mapper 操作
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JSCON简时空 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • A. 视频讲解
  • B. 文字讲解
    • 1、场景简述
      • 2、同步迭代器
        • 3、使用迭代器实现数组打印
          • 4、异步迭代器
            • 5、扩展:Generator & Async Generator
              • 6、参考文档
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档