博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js 迭代器 异步_异步迭代器和生成器入门
阅读量:2510 次
发布时间:2019-05-11

本文共 12545 字,大约阅读时间需要 41 分钟。

js 迭代器 异步

( )

It’s been a long while coming and I feel it’s high time I made a post about it. Asynchronous Iteration could become the next big thing in JavaScript. With the , I think it’s only right to learn about it and you should too.

到现在已经很长一段时间了,我觉得现在是时候发布关于这个的帖子了。 异步迭代可能会成为JavaScript中的下一件大事。 ,我认为这是唯一的了解,您也应该这样做。

In this post, we'll discuss asynchronous iterators as well as generators, where they originated from (there’s always a beginning), what they are used for and how they can make our lives (not just our code) better.

在本文中,我们将讨论异步迭代器以及生成器 ,它们的起源(总是有一个起点),它们的用途以及如何使我们的生活(不仅仅是代码)变得更好。

One person who inspired this post is , his efforts on the Chrome team and the community as a whole have been astounding. Okay, let’s get digging!

启发此帖子的一个人是 ,他在Chrome团队和整个社区中所做的努力令人震惊。 好吧,让我们开始挖掘吧!

( )

I bet you didn't know that the following code block is a thing:

我敢打赌,您不知道以下代码块是一回事:

for await (const info of getApi(apis)) {
console.log(info);}

Yes, it is and as a matter of fact now has a good wide browser support. The code sample iterates over an async operation, getApi, without the need to wait for the operation to resolve.

是的,事实上,现在已经拥有良好的浏览器支持。 该代码示例在异步操作getApi进行迭代,而无需等待操作解决。

( )

Moving on to iterators without first having a recap on how async work in JS could be a bit misleading. Basically when you execute an operation asynchronously, you have room to move on to another task before it finishes executing and that’s exactly what asynchronous functions are. Below is a setTimeout function, the most basic form of asynchronous JavaScript ever written:

继续迭代器而不先回顾一下JS中异步的工作方式可能会引起误解。 基本上,当您异步执行某个操作时,您有空间可以在完成另一个任务之前继续执行它,这正是异步功能。 下面是setTimeout函数,这是有史以来编写的异步JavaScript的最基本形式:

// Say "I have Mac and Cheese"  console.log("I have Mac and Cheese");  // Say "Sure thank you" three seconds from now.   setTimeout(function() {
console.log("Sure thank you"); }, 3000); // Say "Want Some?" console.log("Want some?"); //console logs: > I have Mac and Cheese > Want some? > Sure thank you

( )

Iteration is basically a way of traversing data. It works via a number of concepts which are:

迭代基本上是遍历数据的一种方式。 它通过许多概念起作用,这些概念包括:

Iterables: These are data structures that can be iterated. They show they can be iterated by using the Symbol.iterator protocol. This protocol defines that an object should exhibit iteration behavior.

Iterables :这些是可以迭代的数据结构。 它们显示可以使用Symbol.iterator协议进行迭代。 该协议定义对象应表现出迭代行为。

Iterator: This is an object that is returned by invoking [Symbol.iterator]() on an iterable. Using its next() method, it wraps around each iterated element in the data structure and returns it one by one.

迭代器 :这是通过在可迭代对象上调用[Symbol.iterator]()返回的对象。 使用next()方法,它将数据结构中的每个迭代元素包装起来,并一一返回。

IteratorResult: A new data structure returned by next()

IteratorResultnext()返回的新数据结构

Examples of data structures that can be iterables include arrays, strings and maps. The code block below demonstrates how synchronous iteration works:

可以迭代的数据结构示例包括数组,字符串和映射。 下面的代码块演示了同步迭代的工作方式:

const iterable = ['x', 'y', 'z'];  const iterator = iterable[Symbol.iterator]();  iterator.next() {
value: 'x', done: false } iterator.next() {
value: 'y', done: false } iterator.next() {
value: 'z', done: false } iterator.next() {
value: undefined, done: true }

In the example above, the property value has an iterated element, next() keeps on returning each element in the data structure until it is finished thus the value undefined. For every valid value returned, property done is true, after the last element it reverts to false.

在上面的示例中,属性value具有迭代的元素, next()继续返回数据结构中的每个元素,直到完成为止,因此值undefined 。 对于返回的每个有效值, done属性为true,在最后一个元素之后,属性恢复为false。

Let’s take a more detailed example. Here Symbol.Iterator is used once more to iterate through the letter array in the iterable codebeast:

让我们来看一个更详细的例子。 在这里, Symbol.Iterator再次用于遍历可迭代codebeastletter数组:

const codebeast = {
[Symbol.iterator]: () => {
const letter = [`c`, `o`, `d`, `e`, `b`, `e`, `a`, `s`, `t`]; return {
next: () => ({
done: items.length === 0, value: items.shift() }) } } }

We can iterate through the codebeast object using a for... of loop:

我们可以使用for... of循环遍历codebeast对象:

for (const letter of codebeast) {
console.log(letter) // <- `c` // <- `o` // <- `d` // <- `e` // <- `b` // <- `e` // <- `a` // <- `s` // <- `t` }

( )

Asynchronous iteration works almost like synchronous iteration except that it involves promises. The need for iterating through asynchronous data sources brought about asynchronous iteration. In the code block below, readMemo() cannot return its data asynchronously:

异步迭代的工作原理几乎与同步迭代类似,只是它涉及到承诺。 对异步数据源进行迭代的需求带来了异步迭代。 在下面的代码块中, readMemo()无法异步返回其数据:

for (const word of ourMemo(memoName)) {
console.log(word); }

With asynchronous iteration, the concepts Iterable, Iterator and IteratorResult work a bit differently. In asynchronous iteration, iterables use the method Symbol.asyncIterator. Instead of returning Iterator results directly, the next() method of an async iterator returns a promise. In the code clock below let’s try to make the codebeast iterable asynchronous:

通过异步迭代,Iterable,Iterator和IteratorResult概念的工作方式有所不同。 在异步迭代中,可迭代对象使用Symbol.asyncIterator方法。 而不是直接返回Iterator结果,异步迭代器的next()方法将返回一个promise。 在下面的代码时钟中,让我们尝试使代码codebeast可迭代地实现异步:

const codebeast = {
[Symbol.asyncIterator]: () => {
const letter = [`c`, `o`, `d`, `e`, `b`, `e`, `a`, `s`, `t`]; return {
next: () => Promise.resolve({
done: letter.length === 0, value: letter.shift() }) } } }

We can carry out our iteration asynchronously using a for... await... of loop:

我们可以使用for... await... of循环来异步执行迭代:

for (const letter of codebeast) {
console.log(letter) // <- `c` // <- `o` // <- `d` // <- `e` // <- `b` // <- `e` // <- `a` // <- `s` // <- `t` }

Another way of showing asynchronous iteration is a function that can fetch a series of web APIs in succession:

显示异步迭代的另一种方法是可以连续获取一系列Web API的函数:

const displayApi = server => ({
[Symbol.asyncIterator]: () => ({
x: 0, next() {
if (server.length <= this.x) {
return Promise.resolve({
done: true }) } return fetch(server[this.x++]) .then(response => response.json()) .then(value => ({
value, done: false })) } }) }) const apis = [ `/api/random-names`, `/api/random-beer`, `/api/random-flag`, `/api/random-book` ]; for await (const info of getApi(apis)) {
console.log(info); }

Notice how the code looks synchronous yet will operate asynchronously? Using for...await...of in asynchronous iteration is awesome because it delivers each value once asyncIterator.next() is resolved, it also ensures that asyncIterator.next() is not called for the next item in the array until the current iteration is finished. This enables your responses not to overlap thus they will be returned in the correct manner.

注意代码看起来是同步的,但会异步运行吗? 在异步迭代中使用for...await...of非常棒,因为一旦asyncIterator.next()被解析,它就会传递每个值,还可以确保在数组中的下一项之前不调用asyncIterator.next()当前迭代完成。 这使您的响应不会重叠,因此将以正确的方式返回。

发电机 (Generators)

Another exciting feature introduced in ES6, generators are mainly used to represent sequences that could possibly be infinite. Generators can also be though of as processes that you can resume and pause. The syntax of generators is thus:

ES6中引入的另一个令人兴奋的功能是生成器,主要用于表示可能是无限的序列。 生成器也可以作为可以恢复和暂停的过程。 因此,生成器的语法为:

function* genFunc() {
console.log('One'); yield; console.log('Two'); }

Where function* is a new keyword used for generator functions, yield is an operator which a generator can use to pause itself and also use to receive input and send output. Enough said, let’s proceed to work with generators. The code block below uses a generator to return positive integers:

function*是用于生成器函数的新关键字的情况下, yield是运算符,生成器可以使用该运算符暂停自身,还可以用于接收输入和发送输出。 够了,让我们继续使用发电机。 下面的代码块使用生成器返回正整数:

function* countUp() {
for (var i = 0; true; i++) {
yield i } } for (var i of countUp()) {
console.log(i) }

In the example above, the countUp function is lazily evaluated, it pauses at each yield and waits till another value is asked for. This means the the for... of loop will keep on executing since our integer list is infinite. This brings a host of possibilities that can help us implement asynchronous operations such as loops and conditionals in our functions. Outrightly, generators don’t have a way of representing results of asynchronous operations. To do that, they have to work with promises. Speaking of promises, let’s see how we can iterate through a generator function using the .next method:

在上面的示例中,对countUp函数进行了延迟计算,它在每次yield时暂停,并等待直到要求另一个值。 这意味着for... of循环将继续执行,因为我们的整数列表是无限的。 这带来了很多可能性,可以帮助我们在函数中实现异步操作,例如循环和条件。 坦白地说,生成器没有一种表示异步操作结果的方法。 为此,他们必须兑现承诺。 说到promise,让我们看看如何使用.next方法遍历生成器函数:

function* race() {
var lap1 = yield 20; assert(lap1 === 35); return 55; } var r = race(); var lap2 = r.next(); // => {value: 20, done: false} var lap3 = r.next(35); // => {value: 55, done: true} //if we call r.next() again it will throw an error

In the example above, r.next() is called once to get it to the yield and then called a second time and passed a value which is the result of the yield expression. This way, race() can then proceed to the return statement to return a final result. This can be implemented by calling .next(result) to show that a promise has been fulfilled with result.

在上面的示例中,一次调用r.next()以使其达到yield ,然后再次调用r.next()并传递作为yield表达式结果的值。 这样, race()然后可以继续执行return语句以返回最终结果。 这可以通过调用.next(result)来实现,以显示结果已经兑现了承诺。

But what if our promise that is yielded is rejected? We can show this by using the .throw(error) method:

但是,如果我们的应许被拒绝了怎么办? 我们可以通过使用.throw(error)方法来证明这一点:

var shortcut = new Error('too fast');   function* race() {
try {
yield 100; } catch (h) {
assert(h === shortcut); } } var r = race(); r.next(); // => {value: 100, done: false} d.throw(shortcut);

Just as in the previous example, r.next() is called to obtain the first yield keyword.We use r.throw(error) to signal rejection as it causes our generator to behave like an error was thrown by yield. This automatically triggers the catch block.

和前面的例子一样, r.next()来获得第一个yield r.throw(error)我们使用r.throw(error)来表示拒绝,因为它使我们的生成器表现得就像yield引发了错误一样。 这将自动触发catch块。

Let’s take one more example where we attempt two-way communication with generators. Here next() can actually assign values which are received from the generator:

让我们再举一个例子,我们尝试与生成器进行双向通信。 在这里, next()可以实际分配从生成器接收的值:

function* techInterview() {
const answer = yield 'Who is the CEO of Tesla?'; console.log(answer); if (answer !== 'Elon Musk') return 'No Way!' return 'Okay, on to the next question'; } {
const Iterator = techInterview(); const q = Iterator.next() .value; // Iterator yields question console.log(q); const a = Iterator.next('Scott Hanselmann') .value; // Pass wrong answer back into generator console.log(a); } // Who is the CEO of Tesla? // Scott Hanselmann // No Way! {
const Iterator = techInterview(); const q = Iterator.next() .value; // Iterator yields another question console.log(q); const a = Iterator.next('Jimmy Kimmel') .value; // Pass wrong answer back into generator console.log(a); } // Who is the CEO of Tesla? // Jimmy Kimmel // No Way! {
const Iterator = techInterview(); const q = Iterator.next() .value; // Iterator yields another question console.log(q); const a = Iterator.next('Elon Musk') .value; // Pass correct answer back into generator console.log(a); } // Who is the CEO of Tesla? // Elon Musk // Okay on to the next question

( )

There are lots of ways asynchronous iterators and generators can improve your work flow. I’ve tried them and it sure worked for me. We don’t have to wait for TC39 to give them the general thumbs up before we begin implementing them (or do we? forgive me please :) ). In the end, we are all learning and what is important is to know what works best for you. I’m just going to leave a couple of resources here for further reading:

异步迭代器和生成器可以通过多种方式改善您的工作流程。 我已经尝试过了,它肯定对我有用。 在开始实施它们之前,我们不必等待TC39给予他们普遍的赞许(或者我们?请原谅我:))。 最后,我们都在学习,重要的是要知道什么对您最有效。 我将在此处留下一些资源以供进一步阅读:

翻译自:

js 迭代器 异步

转载地址:http://druwd.baihongyu.com/

你可能感兴趣的文章
解决 Visual Studio 点击添加引用无反应的问题
查看>>
通过镜像下载Android系统源码
查看>>
python字符串格式化 %操作符 {}操作符---总结
查看>>
windows 不能在 本地计算机 启动 Apache
查看>>
iOS开发报duplicate symbols for architecture x86_64错误的问题
查看>>
Chap-6 6.4.2 堆和栈
查看>>
【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
查看>>
C# MySql 连接
查看>>
网络抓包分析方法大全
查看>>
sql 数据类型
查看>>
android 截图
查看>>
WebServicer接口类生成方法。
查看>>
POJ 1740
查看>>
【翻译】火影忍者鸣人 疾风传 终级风暴2 制作介绍
查看>>
http和webservice
查看>>
hdu1879------------prim算法模板
查看>>
jdbc之二:DAO模式
查看>>
MySQL性能优化方法一:缓存参数优化
查看>>
Angular2 - 概述
查看>>
正则表达式tab表示\t
查看>>