hackernews 网址
With the introduction of ES6, we acquired the support for synchronously iterating over data. We could, of course, already iterate over iterable built-in structures like objects or arrays, but the big introduction was the formalization of an implementable interface to create both our iterables and generators.
随着ES6的引入,我们获得了对数据进行同步迭代的支持。 我们当然可以对可迭代对象进行迭代 诸如对象或数组之类的内置结构,但是最大的介绍是可实现接口的形式化,以创建我们的可迭代对象 和发电机。
But what about the scenarios where our iterations are done over data that is obtained from an asynchronous source, such as a set of remote HTTP calls or reading from a file?
但是,如何对从异步源获取的数据(例如一组远程HTTP调用或从文件读取)进行迭代的场景呢?
In this article, we will conduct a practical analysis of the “Asynchronous Iteration” proposal, which is intended to add:
在本文中,我们将对“异步迭代”建议进行实际分析,该建议旨在增加:
“support for asynchronous iteration using the AsyncIterable and AsyncIterator protocols. It introduces a new IterationStatement, for-await-of, and adds syntax for creating async generator functions and methods.”
“支持使用AsyncIterable和AsyncIterator协议进行异步迭代。 它引入了一个新的IterationStatement for-await-of ,并添加了用于创建异步生成器函数和方法的语法。”
For this guide, only basic knowledge of JavaScript (or programming in general) is required. All our examples, which will be presented with some simple TypeScript annotations, can be found in this GitHub repository.
对于本指南,仅需要JavaScript的基本知识(或一般而言的编程)。 我们的所有示例(将带有一些简单的TypeScript注释)将在此GitHub存储库中找到。
同步迭代器和生成器概述 (Recap of Synchronous Iterators and Generators)
In this section, we will do a quick review of synchronous iterators and generators in JavaScript so we can more easily extrapolate them into the asynchronous case.
在本节中,我们将快速回顾一下JavaScript中的同步迭代器和生成器,以便我们可以更轻松地将它们推断为异步情况。
无论如何,迭代是什么? (What is an iteration anyway?)
Let us look into this question by self-realizing what we usually have at hand when iterating. For example, on one side, we have our arrays, strings, etc. being basically our sources. On the other side, we have what we usually use as our means to consume our data via an iteration — namely our for
loops, spread operators, etc.
让我们通过自我实现迭代时通常会遇到的问题来研究这个问题。 例如,在一侧,我们有数组,字符串等。 存在 基本上是我们的资源 另一方面,我们通常将其用作通过迭代消耗数据的方法,即for
循环,散布运算符等。
Based on this, we can look at an iteration as a protocol that, when implemented by our sources, will allow consumers to sequentially “consume” its contents using a set of regular operations. This protocol could then be represented by the following interface:
基于此,我们可以将迭代视为一种协议,当由我们的源实现时,该协议将允许消费者使用一组常规操作顺序“消费”其内容。 然后可以通过以下接口表示该协议:

So, putting it verbosely for those readers who may not be familiar with TS interface descriptions:
因此,为那些可能不熟悉TS接口说明的读者提供了详细的说明:
A
SynchronousIterable
provides a method via aSymbol.iterator
that would return aSynchronousIterator
.SynchronousIterable
通过Symbol.iterator
提供一种方法,该方法将返回SynchronousIterator
。Our
SynchronousIterator
would then return ourIteratorResults
from its implementation of the.next()
method.然后,我们的
SynchronousIterator
将从其对.next()
方法的实现中返回IteratorResults
。The
IteratorResults
would then contain a value to hold the current iterated value as well as adone
flag that is set totrue
after the last item is iterated through (and false while iterating).然后,
IteratorResults
将包含一个值以保存当前的迭代值,以及一个done
标志,该标志在迭代完最后一项后设置为true
(在迭代时为false)。
Note: You can find out more about this by reading the ECMAScript 2021 Language Specification documentation.
注意:您可以通过阅读 ECMAScript 2021语言规范文档 了解更多信息 。
An example of using this interface can be easily showcased by manually iterating over an array:
通过手动遍历数组,可以轻松展示使用此接口的示例:

Sources that implement this interface can also be iterated via a for..of
iteration directive that you have probably made use of at some point:
也可以通过for..of
迭代指令(可以在某个时候使用该指令)来迭代实现此接口的源:

Of course, we would expect sources like the built-in array (as used above) to be iterable naturally. To then showcase it differently, we’ll implement that interface, for example, to generate a range of numbers:
当然,我们希望像内置数组这样的源(如上所用)自然可以迭代。 为了以不同的方式展示它,我们将实现该接口,例如,生成一系列数字:

发电机呢? (What about generators?)
Usually, functions return either a single value or none. We can think of generators as entities that can return, in sequence, multiple values. To this holding of values, it was attributed the concept of yielding.
通常,函数返回一个值或不返回任何值。 我们可以想到发电机 作为可以依次返回多个值的实体。 归因于这种价值观的持有,这归因于收益的概念。

These generator functions do not behave as regular functions, as they are lazily evaluated. So when called, they will return you a generator object that will be responsible for managing its execution. These generators are also iterable, meaning they also implement our interface so we can actually loop over them similarly as above:
这些生成器函数不能按常规函数运行,因为它们是延迟计算的。 因此,当调用它们时,它们将返回一个生成器对象,该对象将负责管理其执行。 这些生成器也是可迭代的 意味着它们还实现了我们的接口,因此我们可以像上面类似地实际遍历它们:

Also, it is also very important to denote that the .next()
function is key to obtaining the next yielded value for these generator objects. This will then produce the expected outputs.
同样,非常重要的一点是, .next()
函数对于获取这些生成器对象的下一个产生值至关重要。 然后将产生预期的输出。
As we can now yield values (instead of state), we can then re-implement our iterable range from Figure 1.4, but now using a generator function:
现在我们可以产生值(而不是状态),因此可以重新实现图1.4中的可迭代范围,但是现在使用了生成器函数:

As we can see, we can now leverage a generator function to simplify our original ranged iterable.
如我们所见,我们现在可以利用生成器函数来简化我们的原始范围可迭代。
异步接口建议 (An Asynchronous Interface Proposal)
After grasping the idea behind the interface definition of an iterable (Figure 1.1), it would be easy to now extend it in a way where every step of our iteration would then return the result of an asynchronous operation. The usual representation of this is via promises:
在掌握了可迭代的接口定义(图1.1)背后的思想之后,现在很容易以某种方式扩展它,即迭代的每一步都将返回异步操作的结果。 通常通过promise来表示:

From the definition above, we can easily identify that the asynchronous operation is indeed when providing the .next()
element of the iteration. Therefore, it is trivial to proceed with implementing it in a way that handles the results as promises. Let us make this clear by adapting our ranged iterator (from Figure 1.5) in this way with a faux delay:
根据上面的定义,我们可以轻松地确定提供迭代的.next()
元素时,异步操作确实存在。 因此,以一种按预期方式处理结果的方式来实施它是微不足道的。 让我们通过使用伪延迟以这种方式适配我们的远程迭代器(图1.5)来明确这一点:

We can use this concept to actually abstract our generator in (1.7). It would then be trivial to implement the same range using an asynchronous generator:
我们可以使用这个概念来实际抽象(1.7)中的生成器。 然后使用异步生成器实现相同范围将变得很简单:

Regardless of how we generate the data, we may simply iterate over the elements as if an asynchronous source was yet another iterable. Actually, it is as long as it implements our interface.
无论我们如何生成数据,我们都可以简单地对元素进行迭代,就好像异步源是另一个可迭代的源一样。 实际上,只要实现我们的接口即可。
To demonstrate this, the next section will use an asynchronous source (a Hacker News top stories feed) that we will then use to manipulate as we would with any other iterable structure.
为了说明这一点,下一部分将使用异步源(《黑客新闻》的最新消息提要),然后我们将使用该异步源来处理其他可迭代结构。
练习题:可迭代的HackerNews (Practical Exercise: a HackerNews Iterable)
Based on the implementation of an asynchronous generator (2.3), it is now trivial to materialize a generator source for our posts. For this example, we will use the HN API:
基于异步生成器(2.3)的实现,现在为我们的帖子实现生成器源变得微不足道了。 在此示例中,我们将使用HN API :

This code simply tucks the asynchronous logic by implementing still the usual interface for an async iterator. For this example, we are limiting the entries to iterate over, which is optional. By yielding each iterated value, we can easily consume this source with the following simple implementation:
该代码通过为异步迭代器实现仍然常用的接口来简单地处理异步逻辑。 对于此示例,我们限制了要迭代的条目,这是可选的。 通过产生每个迭代值,我们可以通过以下简单实现轻松使用此源:

As expected, this loops and renders a list of comments for our source:
如预期的那样,这将循环并为我们的源呈现注释列表:

We can now look at our data source and handle it as a simple data sequence, keeping the full asynchronous fetching and manipulation logic within our generator definition.
现在,我们可以查看数据源并将其作为简单的数据序列进行处理,将完整的异步获取和操作逻辑保留在生成器定义内。
摘要 (Summary)
Hopefully, this article showcases that it is trivial to transform and observe our asynchronous data sources as well as iterables by applying simple language formalities already available in the language specification.
希望本文展示了通过应用语言规范中已有的简单语言形式来转换和观察我们的异步数据源以及可迭代对象是微不足道的。
By generalizing the synchronous case to also cover asynchronous generation, we can now iterate over any iterable source regardless of the nature of the data source — as long as it implements our interface. Looking at our asynchronous data sources as iterables opens a creative potential for our ideas towards more idiomatic and eloquent codebases.
通过将同步情况概括为也涵盖异步生成,我们现在可以迭代任何可迭代的源,而与数据源的性质无关,只要它实现了我们的接口即可。 将我们的异步数据源视为可迭代对象,为我们的想法向更加习惯和雄辩的代码库打开了创造潜力。
For all the code examples, please refer to this GitHub repo.
有关所有代码示例,请参考此GitHub存储库 。
hackernews 网址