hackernews 网址_javascript中的实用异步迭代hackernews故事可迭代

本文介绍了JavaScript中的异步迭代,展示了如何使用AsyncIterable和AsyncIterator协议处理异步数据源,如远程HTTP调用或文件读取。通过实际示例,文章解释了异步迭代的原理及其在异步数据源上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

基于此,我们可以将迭代视为一种协议,当由我们的源实现时,该协议将允许消费者使用一组常规操作顺序“消费”其内容。 然后可以通过以下接口表示该协议:

Image for post
1.1 Interface for defining a synchronous iterable, iterator, and subsequent result for every iteration.
1.1用于定义每次迭代的同步迭代器,迭代器和后续结果的接口。

So, putting it verbosely for those readers who may not be familiar with TS interface descriptions:

因此,为那些可能不熟悉TS接口说明的读者提供了详细的说明:

  • A SynchronousIterable provides a method via a Symbol.iterator that would return a SynchronousIterator.

    SynchronousIterable通过Symbol.iterator提供一种方法,该方法将返回SynchronousIterator

  • Our SynchronousIterator would then return our IteratorResults 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 a done flag that is set to true 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:

通过手动遍历数组,可以轻松展示使用此接口的示例:

1.2) Simple manual iteration. Notice the fact that “done” is set to true when we are over transversing the object.
1.2 Simple manual iteration. Notice the fact that “done” is set to true when we are over-transversing the object.
1.2简单的手动迭代。 注意,当我们过度转换对象时,“ done”被设置为true。

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迭代指令(可以在某个时候使用该指令)来迭代实现此接口的源:

Image for post
1.3 Using for..of to iterate over our source.
1.3使用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:

当然,我们希望像内置数组这样的源(如上所用)自然可以迭代。 为了以不同的方式展示它,我们将实现该接口,例如,生成一系列数字:

Image for post
1.4 A custom implementation of an iterable source that generates a range of numbers from “start” to “end.”
1.4一个可迭代源的定制实现,该可生成源生成从“开始”到“结束”的一系列数字。

发电机呢? (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.

通常,函数返回一个值或不返回任何值。 我们可以想到发电机 作为可以依次返回多个值的实体。 归因于这种价值观的持有,这归因于收益的概念。

Image for post
1.5 Defining a generator function that yields at the time the same 1, 2, 3 sequence.
1.5定义在同一时间产生1、2、3序列的生成器函数。

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:

这些生成器函数不能按常规函数运行,因为它们是延迟计算的。 因此,当调用它们时,它们将返回一个生成器对象,该对象将负责管理其执行。 这些生成器也是可迭代的 意味着它们还实现了我们的接口,因此我们可以像上面类似地实际遍历它们:

Image for post
1.6. Checking the values from our generator function. And yep, the main method of a generator is also .next().
1.6。 检查生成器函数中的值。 是的,生成器的主要方法也是.next()。

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中的可迭代范围,但是现在使用了生成器函数:

Image for post
1.7 Our ranged iterable source now implemented using a generator function.
1.7现在,我们使用生成器函数实现了远程可迭代源。

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来表示:

Image for post
2.1. An interface for asynchronous iterables.
2.1。 异步可迭代对象的接口。

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)来明确这一点:

Image for post
2.2 An asynchronous ranged iteration with for…of.
2.2 for…of的异步范围迭代。

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)中的生成器。 然后使用异步生成器实现相同范围将变得很简单:

Image for post
2.3 Implementation of an asynchronous generator
2.3异步生成器的实现

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

Image for post
3.1 Async generator for the top stories on HN.
3.1用于HN热门新闻的异步生成器。

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:

该代码通过为异步迭代器实现仍然常用的接口来简单地处理异步逻辑。 对于此示例,我们限制了要迭代的条目,这是可选的。 通过产生每个迭代值,我们可以通过以下简单实现轻松使用此源:

Image for post
3.2 Iterating our asynchronous news source.
3.2迭代我们的异步新闻源。

As expected, this loops and renders a list of comments for our source:

如预期的那样,这将循环并为我们的源呈现注释列表:

Image for post
3.3 Iteration result from our HN generator.
3.3 HN生成器的迭代结果。

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存储库

翻译自: https://medium.com/@tapadasalves/practical-asynchronous-iteration-in-javascript-a-hackernews-stories-iterable-f3c7a70466d

hackernews 网址

Hacker News本身也是开源的,为什么还要做iNews?初衷是什么? 赵戈戈:Hacker News从功能和内容本身上来说是个很好的应用,我们最初也是想从开源入手 —— 直接使用,不过HN是甚于Arch实现的,我们对Arch 并不熟悉,所以决定自己写,以便功能扩展。 关于初衷。从产品上讲,要从我和搭档 @sofish说起。我们都是苹果的忠实用户,经常会互相分享一些应用,久而久之也就萌发了这个念头:做一个分享苹果新闻和应用的社区,对于苹果在中国这几年设备数据大增,应该有很多人跟我们有同样的需求,于是就开始做了;从技术上讲,它的结构类似于Hacker News,而外观应该更漂亮,并且要适合移动应用阅读。最终我们动手实现了它,并上线了http://inews.io。虽然现在还没有完全做到期望值,但最起码迈出了第一步;从程序本身来讲,上线了一段时间后,很多朋友看到都希望在自己站点上使用,后来越来越多的人寻求使用并提供建议,基于我们对开源的开放态度,最终决定放出来给大家使用。 iNews 在技术上是如何实现的? 赵戈戈:iNews基于PHP,使用Mysql存储,phpmig进行数据库版本管理。框架上,后端采用了我自己写的Restful框架 Pagon来开发,前端使用了@sofish的 typo.css, validator.js等开源库。第一版本上线前我们希望从最基本的功能开始,上线 > 快速迭代。整个开发过程非常快,只用了一天半的时间就实现了。后续做了些优化和修复就上线了。在服务上我们也采用一些不错的第三方服务:用SendGrid发送邮件,用NewRelic做应用监控,用Dropbox做数据库备份等等。 这里再补充一点:从技术选型上,技术适应产品才是最重要的,不要强迫自己使用的是PHP 、Node或者Ruby等。选择基于PHP的Pagon这个框架,让我们可以更快速实现iNews.io的功能。 总共有几名开发人员?这种UGC项目的技术难点和重点是什么?你们是如何解决的? 赵戈戈:只有我和搭档@sofish两个人。开源之后应该会陆续会有一些同学加入,实际上目前已经有一些同学在一起开发。对于iNews来说,技术上基本没太多难点,主要有几个点需要关注:安全性、性能、易用、适配(Responsive)、社会化接入等。 安全性主要是XSS和数据库过滤。Pagon框架已实现自动XSS处理的,只要开启了safe_query 的选项,在模板渲染的过程中会自动做XSS过滤。数据库方面使用的一个paris库,它本身使用PDO来处理SQL,PDO本身会对数据进行转义处理再存入。 性能其实是个很泛的话题,iNews.io数据样本太少,还不好看出性能到底如何,就目前的平均输出时间来看只有30ms左右,前端方面使用Google Pagespeed测试是:移动,85/100;桌面 95/100;这比很多网站分数都要高。高性能跟逻辑简单和实现方法都有关系,如果需要很好的性能需要考虑到方方面面,我这里先简单说PHP的基本观点:代码越简单越好,不要使用太多魔术方法,尽量使用PHP 内置的方法,使用最新的稳定版5.4,服务器安装APC扩展,使用Nginx FPM模式运行PHP。其次Pagon框架本身开发过程也对性能有很高的要求,所以在代码质量和性能上也下了不少功夫,这也是应用性能的基础。在数据库方面只做了索引优化来达到更好的查询性能。性能还涉及到很多,做为一个刚初出茅庐的应用来说还没有足够完善也不需要把性能放到第一位,在这里就先不说还没有做到的。 而在前端,跨终端适配应该是现代应用最应该做的支持。@sofish 在这一块有很多的研究,所以我们的 iNews 是可以在移动设备上很好的访问的。 社会化接入这块其实也并不是什么难点,只需要有很好的封装就可以解决问题,重新开发代价稍大。我觉得 PHP 第三方认证的库都做的很一般,但还是有个opauth的第三方认证库,封装有点凌乱,但凑合着能用。如果是Node的话,这一块有很多很不错的库,比如everyauth和passport,如果PHP社区可以像Node社区一样活跃那问题就可以更好解决了。 iNews在内容推荐上采用了什么样的机制或算法? 赵戈戈:iNews最初是参照Hacker News的算法来做的,后期将评论也加入了权重。因为觉得对于这种社区来说,评论是很重要的一块,评论代表着交流,有交流就证明内容的价值有可能存在,如果只有“顶”才算权重,那激烈的讨论可能会显得不太公平。但若是每个评论的权重和每个“顶”的权重一样,又显得不太合理,“顶”是认可的意思,评论是交流的意思,所以评论应该稍低于“顶”的权重,这样做才比较合理。最终是这么来做的。 iNews 有哪些创新性的东西? 赵戈戈:如果说创新的话,我想提一个设计模式:MOVE。应该有不少人看到过过这个设计模式,摒弃了MVC传统老套的做法。采用了Model、Operator、View 和 Event 来梳理编码流程。其中 Operator可能是大家最不解的一个地方,其实也是最具创新意义的地方,Opeartor从字面意思来理解就是:操作器。Opeartor的出现摈弃了控制器重用性和代码混杂的局面,将每个操作都拆分成一个独立的操作器,组织成一个树形的流程来封装使用,对于编码流程来说是一个梳理。iNews里面有一些对操作器的浅显理解和实现,但并没有完全使用操作器来做,还是主要使用MVC作为基础,这种尝试会慢慢变得成熟,并可能逐步完全采用这种模式来开发。 标签:iNews
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值