javascript迭代器

by rajaraodv

通过rajaraodv

JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, Iterators, Generators, Async/Await, and Async Iterators — All Explained Simply)

Some JavaScript (ECMAScript) features are easier to understand than others. Generators look weird — like pointers in C/C++. Symbols manage to look like both primitives and objects at the same time.

一些JavaScript(ECMAScript)功能比其他功能更易于理解。 Generators看起来很奇怪-就像C / C ++中的指针一样。 Symbols设法同时看起来像图元和对象。

These features are all inter-related and build on each other. So you can’t understand one thing without understanding the other.

这些功能都是相互关联的,并且相互构建。 因此,您无法不理解另一件事就无法理解。

So in this article, I’ll cover symbols,global symbols,iterators, iterables, generators , async/await and async iterators. I’ll explain “why” they are there in the first place and also show how they work with some useful examples.

因此,在本文中,我将介绍symbolsglobal symbolsiteratorsiterables iteratorsgeneratorsasync/awaitasync iterators我将首先解释“ 为什么 ”,并通过一些有用的示例说明它们的工作原理。

This is relatively advanced subject, but it’s not rocket science. This article should give you a very good grasp of all these concepts.

这是相对高级的学科,但不是火箭科学。 本文应该使您对所有这些概念都有很好的了解。

OK, let’s get started.?

好,让我们开始吧。

符号 (Symbols)

In ES2015, a new (6th) datatype called symbol was created.

在ES2015中,创建了一个新的(第六个)数据类型,称为symbol

为什么? (WHY?)

The three main reasons were:

三个主要原因是:

原因1-添加具有向后兼容性的新核心功能 (Reason 1 — Add new core-features with backward compatibility)

JavaScript developers and the ECMAScript committee (TC39) needed a way to add new object properties without breaking existing methods like for in loops or JavaScript methods likeObject.keys.

JavaScript开发人员和ECMAScript委员会( TC39 )需要一种方法来添加新的对象属性,而又不破坏for in方法(如for in循环)或JavaScript方法(如Object.keys

For example, if I have an object, var myObject = {firstName:'raja', lastName:'rao'} and if I runObject.keys(myObject) it would return[firstName, lastName] .

例如,如果我有一个对象var myObject = {firstName:'raja', lastName:'rao'}并且如果我运行Object.keys(myObject) ,它将返回[firstName, lastName]

Now if we add another property, say newProperty to myObject , and if you run Object.keys(myObject) it should still return old values (that is, somehow make it ignore the newly added newproperty), and show just[firstName, lastName] — and not [firstName, lastName, newProperty] . How to do that?

现在,如果我们添加另一个属性,说newPropertymyObject ,如果你运行Object.keys(myObject)应该 仍然返回旧值(即,以某种方式使之忽略新加入的newproperty ),并只显示[firstName, lastName] —而不是[firstName, lastName, newProperty] 。 怎么做?

We couldn’t really do this earlier, so a new data type called Symbols was created.

我们无法真正做到这一点,因此创建了一个称为Symbols的新数据类型。

If you add newProperty as a symbol, then Object.keys(myObject) would ignore this (as it doesn’t know about it), and still return [firstName, lastName] !

如果将newProperty添加为符号,则Object.keys(myObject)将忽略它(因为它不知道),并且仍然返回[firstName, lastName]

原因2-避免名称冲突 (Reason 2 — Avoid name collisions)

They also wanted to keep these properties unique. This way they can keep adding new properties (and you can add object properties) to global without worrying about name-collisions.

他们还希望保持这些属性的唯一性。 这样,他们可以继续向全局添加新属性(并且可以添加对象属性),而不必担心名称冲突。

For example, say that you have an object where you are adding a custom toUpperCase to global Array.prototype .

例如,假设您有一个要将自定义toUpperCase添加到全局Array.prototype

Now, imagine you loaded another library (or ES2019 came out) and it had a different version of Array.prototype.toUpperCase. Then your function might break because of name collision.

现在,假设您加载了另一个库(或ES2019出来了),并且它具有Array.prototype.toUpperCase.的不同版本Array.prototype.toUpperCase. 然后,您的功能可能会由于名称冲突而中断。

So how do you resolve this name collision that you may not know about? That’s where Symbols come in. They internally create unique values that allow you to create add properties without worrying about name collision.

那么,如何解决您可能不知道的名称冲突呢? 这就是Symbols出现的地方。它们在内部创建唯一值,使您可以创建添加属性而不必担心名称冲突。

原因3-通过“知名”符号启用对核心方法的挂钩 (Reason 3 —Enable hooks to core methods via “Well-known” Symbols)

Suppose you want some core function, sayString.prototype.search to call your custom function. That is, ‘somestring’.search(myObject); should call myObject’s search function and pass ‘somestring’ as a parameter! How do we do that?

假设您想要一些核心函数,例如String.prototype.search以调用您的自定义函数。 也就是说, 'somestring'.search(myObject); 应该调用myObject's搜索功能并传递'somestring'作为参数! 我们该怎么做?

This is where ES2015 came up with a bunch of global symbols called “well-known” symbols. And as long as your object has one of of those symbols as a property, you can redirect core functions to call your function!

这是ES2015提出了一系列称为“知名”符号的全局符号的地方。 只要您的对象具有这些符号之一作为属性,就可以重定向核心函数以调用您的函数!

We can’t talk much about this right now, so I’ll go into all details a bit later in this article. But first, let’s learn about how Symbols actually work.

我们现在不能对此进行过多讨论,因此在本文的稍后部分将详细介绍所有细节。 但是首先,让我们了解符号的实际工作方式。

创建符号 (Creating Symbols)

You can create a symbol by calling a global function/object called Symbol . That function returns a value of datatype symbol.

您可以通过调用名为Symbol的全局函数/对象来创建Symbol 。 该函数返回数据类型symbol的值。

Note: Symbols might appear like Objects because they have methods, but they are not — they are primitives. You can think of them as “special” objects that have some similarities to regular objects, but that don’t behave like regular objects.

注意:符号可能看起来像对象,因为它们具有方法,但它们却不是-它们是基元。 您可以将它们视为“特殊”对象,这些对象与常规对象有些相似,但是行为却不像常规对象。

For example: Symbols have methods just like Objects, but unlike objects they are immutable and unique.

例如:符号具有与对象一样的方法,但是与对象不同,它们是不可变的且唯一的。

不能通过“ new”关键字创建符号 (Symbols can’t be created by “new” keyword)

Because symbols are not objects and the new keyword is supposed to return an Object, we can’t use new to return a symbols datatype.

因为符号不是对象,并且new关键字应该返回Object,所以我们不能使用new来返回symbols数据类型。

var mySymbol = new Symbol(); //throws error

符号带有“描述” (Symbols have “description”)

Symbols can have a description — it’s just for logging purposes.

符号可以有描述-仅用于记录目的。

//mySymbol variable now holds a "symbol" unique value//its description is "some text"const mySymbol = Symbol('some text');

符号是唯一的 (Symbols are unique)

const mySymbol1 = Symbol('some text');const mySymbol2 = Symbol('some text');mySymbol1 == mySymbol2 // false

如果我们使用“ Symbol.for”方法,则符号的行为就像单例 (Symbols behave like a singleton if we use “Symbol.for” method)

Instead of creating a symbol via Symbol() , you can create it via Symbol.for(<key>). This takes a “key” (string) to create a Symbol. And if a symbol with that key already exists, it simply returns the old symbol! So it behaves like a singleton if we use the Symbol.for method.

可以通过Symbol.for(<ke y>)创建symbol ,而不是通过Symbol()创建symbol 。 这需要一个“键”(字符串)来创建一个符号。 并且,如果已经存在一个以th为键的符号,它将简单地返回旧符号! 因此,如果我们e the Symb ol.for方法,它的行为就像一个单例。

var mySymbol1 = Symbol.for('some key'); //creates a new symbolvar mySymbol2 = Symbol.for('some key'); // **returns the same symbolmySymbol1 == mySymbol2 //true

The real reason to use the .for is to create a Symbol in one place and access the same Symbol from some other place.

使用.for的真正原因是在一个位置创建一个Symbol,然后从另一个位置访问该Symbol。

Caution: Symbol.for will make the symbol non-unique in the sense that you’ll end up overriding the values if the keys are the same! So try to avoid this if possible!

注意: Symbol.for将使符号不唯一,因为如果相同,最终将覆盖值! 因此,请尽可能避免这种情况!

Symbol的“描述”与“键” (Symbol’s “description” versus “key”)

Just to make things clearer, if you don’t use Symbol.for , then Symbols are unique. However, if you use it, then if your key is not unique, then the symbols returned will also be not unique.

为了使事情更清楚,如果您不使用Symbol.for ,那么Symbols是唯一的。 但是,如果使用它,则key不是唯一的,则返回的符号也将不是唯一的。

符号可以是对象属性键 (Symbols can be an object property key)

This is a very unique thing about Symbols — and also most confusing. Although they appear like an object, they are primitives. And we can attach a symbol to an Object as a property key just like a String.

关于符号,这是非常独特的事情,也是最令人困惑的。 尽管它们看起来像一个对象,但它们是基元。 我们可以像在字符串上一样,将符号作为属性键附加到对象。

In fact, this is one of the main ways of using Symbols — as object properties!

实际上,这是使用符号作为对象属性的主要方法之一!

Note: Object properties that are symbols are known as “keyed properties”.

注意:作为符号的对象属性称为“键控属性”。

括号运算符与点运算符 (Brackets operator vs. dot operator)

You cannot use a dot operator because dot operators only work on string properties, so you should use a brackets operator.

您不能使用点运算符,因为点运算符仅适用于字符串属性,因此应使用方括号运算符。

使用符号的3个主要原因-回顾 (3 main reasons to use Symbols — a review)

Let’s revisit the three main reasons now that we know how Symbols work.

现在我们了解符号的工作原理,让我们重新回顾三个主要原因。

原因1:符号对于循环和其他方法不可见 (Reason #1 — Symbols are invisible to loops and other methods)

The for-in loop in the example below loops over an object obj but it doesn’t know (or ignores)prop3 and prop4 because they are symbols.

该换在下面在对象循环的例子循环obj ,但它不知道(或忽略) prop3prop4因为他们是符号。

Below is another example where Object.keys and Object.getOwnPropertyNames are ignoring property names that are Symbols.

下面是另一个示例,其中Object.keysObject.getOwnPropertyNames忽略了作为符号的属性名称。

原因2 –符号是唯一的 (Reason #2 — Symbols are unique)

Suppose you want a feature called Array.prototype.includes on the global Array object. It will collide with the default includes method that JavaScript (ES2018) comes with out-of-the-box. How do you add it without colliding?

假设您要在全局Array对象上使用一个名为Array.prototype.includes的功能。 它会与JavaScript(ES2018)附带的默认includes方法冲突。 如何添加它而不发生冲突?

First, create a variable with proper name includes and assign a symbol to it. Then add this variable (now a symbol), to the global Array using bracket notation. Assign any function you want.

首先,创建一个具有适当名称includes的变量,并为其分配符号。 然后使用括号表示法将此变量(现在是符号)添加到全局Array 。 分配所需的任何功能。

Finally call that function using bracket notation. But note that you must pass the actual symbol within the brackets like: arr[includes]() and not as a string.

最后使用括号表示法调用该函数。 但请注意,您必须在括号内传递实际符号,例如: arr[includes]()而不是字符串。

原因3.众所周知的符号(即“全局”符号) (Reason 3. Well-known Symbols (that is, “global” symbols))

By default, JavaScript auto-creates a bunch of symbol variables and assigns them to the global Symbol object ( yeah, the same Symbol()we use to create symbols).

默认情况下,JavaScript自动创建一堆符号变量,并将它们分配给全局Symbol对象(是的,我们用来创建符号的是相同的Symbol() )。

In ECMAScript 2015, These symbols are then added to core methods such as String.prototype.search and String.prototype.replace of core objects such as arrays and strings.

然后在ECMAScript 2015中,将这些符号添加到核心方法(如数组和字符串)的核心方法(如String.prototype.searchString.prototype.replace中。

Some examples of these symbols are: Symbol.match, Symbol.replace, Symbol.search, Symbol.iterator and Symbol.split.

这些符号的一些示例是: Symbol.matchSymbol.replaceSymbol.searchSymbol.iteratorSymbol.split

Since these global symbols are global and exposed, we can make core methods call our custom functions instead of internal ones.

由于这些全局符号是全局的,暴露的,我们可以使核心方法调用,而不是内部那些我们自定义功能。

示例: Symbol.search (An Example: Symbol.search)

For example, String object's String.prototype.search public method searches for a regExp or a string and returns the index if found.

例如,String对象的String.prototype.search公共方法搜索regExp或字符串,如果找到则返回索引。

In ES2015, it first checks if Symbol.search method is implemented in the query regExp (RegExp object). If so, then it calls that function and delegates the work to that. And core-objects like RegExp implements the Symbol.search symbol that actually does the work.

在ES2015中,它首先检查查询regExp(RegExp对象)中是否实现了Symbol.search方法。 如果是这样,则它将调用该函数并将工作委托给该函数。 诸如RegExp之类的核心对象实现了实际上可以完成工作的Symbol.search符号。

Symbol.search的内部工作方式(默认行为) (Inner workings of Symbol.search (DEFAULT BEHAVIOR))

  1. Parse ‘rajarao’.search(‘rao’);

    解析'rajarao'.search('rao');

  2. Convert “rajarao” into String Object new String(“rajarao”)

    将“ rajarao”转换为字符串对象new String(“rajarao”)

  3. Convert “rao” into RegExp object new Regexp(“rao”)

    将“ rao”转换成new Regexp(“rao”) RegExp对象new Regexp(“rao”)

  4. Call search method of “rajarao” String object.

    调用“ rajarao”字符串对象的search方法。

  5. search method internally calls Symbol.search method on “rao” object (delegates the search back to the “rao” object) and pass the “rajarao”. Something like this: "rao"[Symbol.search]("rajarao")

    search方法在内部对“ rao”对象调用Symbol.search方法(将搜索委托回“ rao”对象)并传递“ rajarao”。 像这样的东西: "rao"[Symbol.search]("rajarao")

  6. "rao"[Symbol.search]("rajarao") returns index result as 4to search function and finally, search returns 4 back to our code.

    "rao"[Symbol.search]("rajarao")将索引结果作为4返回到search函数,最后, search4返回到我们的代码。

The below pseudo-code snippet shows how the code internally works:

以下伪代码段显示了代码内部的工作方式:

But the beauty is that, you no longer have to have pass RegExp. You can pass any custom object that implements Symbol.search and return whatever you want and this will continue to work.

但是美丽之处在于,您不再需要通过RegExp。 您可以传递实现Symbol.search任何自定义对象,然后返回所需的任何内容,这将继续起作用。

Let’s take a look.

让我们来看看。

自定义String.search方法以调用我们的函数 (Customizing the String.search method to call our function)

The below example shows how we can make String.prototype.search call our Product class’s search function — thanks to Symbol.search global Symbol.

下面的示例演示了如何使String.prototype.search调用Product类的搜索功能-感谢Symbol.search全局Symbol

Symbol.search的内部工作原理(自定义行为) (Inner workings of Symbol.search (CUSTOM BEHAVIOR))

  1. Parse ‘barsoap’.search(soapObj);

    解析'barsoap'.search(soapObj);

  2. Convert “barsoap” into String Object new String(“barsoap”)

    将“ barsoap”转换为字符串对象new String(“barsoap”)

  3. Since soapObj is already an object, don’t do any conversion

    由于soapObj已经是一个对象,所以请勿进行任何转换

  4. Call search method of “barsoap” String object.

    调用“ barsoap”字符串对象的search方法。

  5. search method internally calls Symbol.search method on “soapObj” object (that is, it delegates the search back to the “soapObj” object) and pass the “barsoap”. Something like this: soapObj[Symbol.search]("barsoap")

    search方法在内部对“ soapObj ”对象调用Symbol.search方法(即,将搜索委派回“ soapObj ”对象)并传递“ barsoap”。 像这样的东西: soapObj[Symbol.search]("barsoap")

  6. soapObj[Symbol.search]("barsoap") returns the index result as FOUND to search function and finally, search returns FOUND back to our code.

    soapObj[Symbol.search]("barsoap")将索引结果作为FOUND返回到search函数,最后, searchFOUND返回到我们的代码。

Hopefully you have a good grasp of Symbols now.

希望您现在对符号有了很好的了解。

OK, let’s move on to Iterators.

好的,让我们继续迭代器。

迭代器和可迭代 (Iterators and Iterables)

为什么? (WHY?)

In almost all our apps, we are constantly dealing with lists of data and we need to display that data in the browser or mobile app. Typically we write our own methods to store and extract that data.

在几乎所有应用程序中,我们一直在处理数据列表,我们需要在浏览器或移动应用程序中显示该数据。 通常,我们编写自己的方法来存储和提取该数据。

But the thing is, we already have standard methods like the for-of loop and spread operator () to extract collections of data from standard objects like arrays, strings, and maps. Why can’t we use these standard methods for our Object as well?

但事实是,我们已经有了诸如for-of循环和散布运算符( )之类的标准方法,可以从诸如数组,字符串和映射之类的标准对象中提取数据集合。 为什么我们也不能对我们的对象使用这些标准方法?

In the example below, we can’t use a for-of loop or spread operator to extract data from our Users class. We have to use a custom get method.

在下面的示例中,我们不能使用for-of循环或散布运算符从Users类提取数据。 我们必须使用自定义的get方法。

But, wouldn’t it be nice to be able to use these existing methods in our own objects? In order to achieve this, we need to have rules that all developers can follow and make their objects work with existing methods.

但是,能够在我们自己的对象中使用这些现有方法不是很好吗? 为了实现这一目标,我们需要制定规则,所有开发人员都可以遵循这些规则,并使他们的对象与现有方法一起使用。

If they follow these rules to extract data from their objects, then such objects are called “iterables”.

如果他们遵循这些规则从其对象中提取数据,则这些对象称为“可迭代对象”。

The rules are:

规则是:

  1. The main object/class should store some data.主要对象/类应存储一些数据。
  2. The main object/class must have the global “well-known” symbol symbol.iterator as its property that implements a specific method as per rules #3 to #6.

    主对象/类必须具有全局“知名”符号symbol.iterator作为其属性,该属性根据规则3至6实施特定方法。

  3. This symbol.iterator method must return another object — an “iterator” object.

    symbol.iterator方法必须返回另一个对象-“ iterator”对象。

  4. This “iterator” object must have a method called the next method.

    该“迭代器”对象必须具有称为next方法的方法。

  5. The next method should have access to the data stored in rule #1.

    next方法应该可以访问规则1中存储的数据。

  6. And if we call iteratorObj.next(), it should return some stored data from rule #1 either as {value:<stored data>, done: false} format if it wants to return more values, or as {done: true} if it doesn’t want to return any more data.

    如果我们调用iteratorObj.next() ,则它应该从规则#1返回一些存储的数据,如果要返回更多值,则应以{value:<stored data>, done: false}格式返回, or as { done : true}如果它不想返回更多数据。

If all those 6 rules are followed, then the main object is called as an “iterable” from rule #1. The object it returned is called an “iterator”.

如果遵循所有这6条规则,则从规则#1将主对象称为“ 可迭代 ”。 它返回的对象称为“ 迭代器 ”。

Let’s take a look at how we can make our Users object and iterable:

让我们看一下如何使Users对象成为可迭代对象:

Important note: If we pass an iterable (allUsers) for-of loop or spread operator, internally they call <iterable>[Symbol.iterator]() to get the iterator (like allUsersIterator ) and then use the iterator to extract data.

重要说明 :如果我们传递iterable ( allUsers )的for-of循环或散布运算符,则在内部它们调用<iterable>[Symbol.itera tor]()来获取迭代器(like allUsersIt erator),然后使用迭代器提取数据。

So in a way, all those rules are there to have a standard way to return an iterator object.

因此,在某种程度上,所有这些规则都具有一种标准的方式来返回iterator对象。

发电机功能 (Generator functions)

为什么? (WHY?)

There are two main reasons:

主要有两个原因:

  1. provide higher-level abstraction to iterables为可迭代对象提供更高级别的抽象
  2. Provide newer control-flow to help with things like “callback-hell”.提供更新的控制流来帮助处理诸如“回叫”之类的问题。

Let’s check them out in detail.

让我们详细检查一下。

原因1-迭代器的包装 (REASON 1 — A wrapper for iterables)

Instead of making our class/object an iterable by following all those rules, we can simply create something called as a “Generator” method to simplify things.

除了遵循所有这些规则使我们的类/对象iterable ,我们还可以简单地创建一个称为“ Generator”方法的东西来简化事情。

Below are some of the main points about Generators:

以下是有关生成器的一些要点:

  1. Generator methods have a new *<myGenerator> syntax inside a class, and Generator functions have the syntax function * myGenerator(){}.

    生成器方法在类内部具有新的*<myGenerat或>语法,并且生成器函数具有s yntax function * myGenerat或(){}。

  2. Calling generators myGenerator()returns a generator object that also implements the iterator protocol (rules), so we can use this as an iterator return value out-of-the-box.

    调用generators myGenerator()返回一个generator对象,该对象也实现了iterator协议(规则),因此我们可以将其用作现成的iterator返回值。

  3. Generators use a special yield statement to return data.

    生成器使用特殊的yield语句返回数据。

  4. yield statements keep track of previous calls and simply continue from where it left off.

    yield语句跟踪先前的调用,并从中断处继续。

  5. If you use yield inside a loop, it’ll only execute once each time we call the next() method on the iterator.

    如果在循环中使用yield ,则每次我们在迭代器上调用next()方法时,它只会执行一次。

范例1: (Example 1:)

The below code shows you how you can use a generator method (*getIterator()) instead of using the Symbol.iterator method and implementing the next method that follows all the rules.

下面的代码显示了如何使用生成器方法( *getIterator() )而不是使用Symbol.iterator方法并实现遵循所有规则的next方法。

范例2: (Example 2:)

You can simplify it even further. Make a function a generator (with * syntax), and use yield to return values one at a time like shown below.

您可以进一步简化它。 使一个函数生成器(使用*语法),并使用yield返回一个值,如下所示。

Important Note: Although in the examples above, I’m using the word “iterator” to represent allUsers , it’s really a generator object .

重要说明 :尽管在上面的示例中,我使用“迭代器”一词来表示allUsers ,但它实际上是一个generator对象。

The generator object has methods like throw and return in addition to the next method! But for practical purposes, we can use the returned object as just “iterator”.

除了next方法外,生成器对象还具有诸如throwreturn之类的方法! 但是出于实际目的,我们可以将返回的对象用作“迭代器”。

原因2-提供更好和更新的控制流 (REASON 2 — Provide better and newer control-flows)

Help provide new control-flows that helps us write programs in new ways and solve things like “callback hell”.

帮助提供了新的控制流,可帮助我们以新的方式编写程序并解决诸如“回调地狱”之类的问题。

Notice unlike a normal function, the generator function can yield (store the function’s state and return value) and also be ready to take additional input values at the point where it yielded.

请注意,与普通函数不同,生成器函数可以yield (存储函数的statereturn值),并且还可以在产生点处获取其他输入值。

In the picture below, every time it sees yield, it can return the value. You can use generator.next(“some new value”) and pass the new value at the point where it yielded.

在下图中,每次看到yield ,它都可以返回该值。 您可以使用generator.next(“some new value”)并将新值传递到产生值的位置。

The below example shows in more concrete terms how the control-flow works:

下面的示例更具体地显示了控制流的工作方式:

生成器语法和用法 (Generator syntax and usage)

Generator functions can be used in the following ways:

生成器功能可以通过以下方式使用:

我们可以在“ yield”之后添加更多代码(与“ return”语句不同) (We can have more code after “yield” (unlike the “return” statement))

Just like the return keyword, the yield keyword also returns the value — but it allows us to have code after yielding!

就像return关键字一样, yield关键字也返回值-但是它允许我们在yield之后获得代码!

您可以有多个收益 (You can have multiple yields)

通过“ next”方法来回发送值到生成器 (Sending values back-and-forth to generators via the “next” method)

The iterators next method can also pass values back into the generator as shown below.

迭代器的next方法还可以将值传递回生成器,如下所示。

In fact, this feature enables generators to eliminate “callback hell”. You’ll learn more about this in a bit.

实际上,此功能使生成器可以消除“回调地狱”。 您将很快了解更多有关此的信息。

This feature is also used heavily in libraries like redux-saga.

该功能在redux-saga之类的库中也大量使用。

In the example below, we call the iterator with an empty next() call to get the question. And then, we pass 23 as the value when we call the next(23) the 2nd time.

在下面的示例中,我们使用空的next()调用迭代器以获取问题。 然后,当我们第二次调用next(23)时,将23作为值传递。

生成器有助于消除“回调地狱” (Generators help eliminate “callback hell”)

You know that we get into callback hell if we have multiple asynchronous calls.

您知道,如果我们有多个异步调用,就会陷入回调地狱 。

The example below shows how libraries such as “co” use the generator feature that allows us to pass a value via the next method to help us write async code synchronously.

下面的示例说明了诸如“ co ”之类的库如何使用生成器功能,该功能允许我们通过next方法传递值,以帮助我们同步编写异步代码。

Notice how the co function passes the result from the promise back to the generator via next(result) in Step #5 and Step #10.

请注意,在第5步和第10步中, co函数如何将promise的结果通过next(result)返回给生成器。

OK, let’s move on to async/await.

好的,让我们继续进行异步/等待。

异步/等待 (ASYNC/AWAIT)

为什么? (WHY?)

As you saw earlier, Generators can help eliminate “callback hell”, but you need some 3rd party library like co to make that happen. But “callback hell” is such a big problem, the ECMAScript committee decided to create a wrapper just for that aspect of Generator and came out with the new keywords async/await.

如您先前所见,Generators可以帮助消除“回调地狱”,但是您需要像co这样的第三方图书馆来实现这一目标。 但是“回调地狱”是一个很大的问题,ECMAScript委员会决定仅针对Generator的这一方面创建一个包装器,并推出了新的关键字async/await

The differences between Generators and Async/Await are:

生成器和异步/等待之间的区别是:

  1. async/await uses await instead of yield.

    async / await使用await而不是yield

  2. await only works with Promises.

    await仅适用于Promises。

  3. Instead of function*, it uses the async function keyword.

    代替function* ,它使用async function关键字。

So async/await is essentially a subset of Generators and has a new syntactic sugar.

因此async/await本质上是Generator的子集,并具有新的语法糖。

The async keyword tells the JavaScript compiler to treat the function differently. The compiler pauses whenever it reaches the await keyword within that function. It assumes that the expression after await returns a promise and waits until the promise is resolved or rejected before moving further.

async关键字告诉JavaScript编译器以不同的方式对待函数。 只要编译器在该函数中到达await关键字,它就会暂停。 它假定await之后的表达式返回一个promise,并等待直到promise被解决或被拒绝后再继续移动。

In the example below, the getAmount function is calling two asynchronous functions getUser and getBankBalance . We can do this in a promise, but using async await is more elegant and simple.

在下面的示例中, getAmount函数正在调用两个异步函数getUsergetBankBalance 。 我们可以按承诺来做到这一点,但是使用async await更加优雅和简单。

异步运算符 (ASYNC ITERATORS)

为什么? (WHY?)

It’s a pretty common scenario where we need to call async functions in a loop. So in ES2018 (completed proposal), the TC39 committee came up with a new Symbol Symbol.asyncIterator and also a new construct for-await-of to help us easily loop over async functions .

这是一个很常见的场景,我们需要在循环中调用异步函数。 因此,在ES2018(已完成的提案)中,TC39委员会提出了一个新的Symbol Symbol.asyncIterator和一个新for-await-of以帮助我们轻松地遍历异步函数。

The main difference between regular Iterator objects and Async Iterators is as follows:

常规Iterator对象与Async Iterators之间的主要区别如下:

迭代器对象 (Iterator object)

  1. Iterator object' s next() method returns value like {value: ‘some val’, done: false}

    迭代器对象的next()方法返回类似{value: 'some val', done: false}

  2. Usage : iterator.next() //{value: ‘some val’, done: false}

    用法: iterator.next() //{value: 'some val', done: false}

异步迭代器对象 (Async Iterator object)

  1. Async Iterator object’s next() method returns a Promise that later resolves into something like {value: ‘some val’, done: false}

    异步迭代器对象的next()方法返回一个Promise ,稍后将其分解为{value: 'some val', done: false}

  2. Usage: iterator.next().then(({ value, done })=> {//{value: ‘some val’, done: false}}

    用法: iterator.next().then(({ value, done })=> {//{value: 'some val', done: fals e}}

The below example shows how for-await-of works and how you can use it.

下面的示例显示了for-await-of工作方式以及如何使用它。

摘要 (SUMMARY)

Symbols — provide a globally unique data type. You use them mainly as object properties to add new behaviors so you don’t break standard methods like Object.keys and for-in loops.

符号 -提供全局唯一的数据类型。 您主要将它们用作对象属性来添加新的行为,这样就不会破坏Object.keysfor-in循环之类的标准方法。

Well-known symbols — are auto-generated symbols by JavaScript and can be used to implement core methods in our custom objects

众所周知的符号 -是JavaScript自动生成的符号,可用于在我们的自定义对象中实现核心方法

Iterables — are any objects that store a collection of data and follow specific rules so that we can use standard for-of loop and ... spread operators to extract data from within them.

Iterables-可存储数据集合并遵循特定规则的任何对象,以便我们可以使用标准的for-of循环和... spread运算符从其中提取数据。

Iterators — are returned by Iterables and have the next method — it’s what actually extracts the data from an iterable.

迭代器 -由Iterables返回,并具有next方法-这实际上是从iterable提取数据的原因。

Generators —provide higher level abstraction to Iterables. They also provide new control-flows that can solve things like callback-hell and provide building blocks for things like Async/Await.

生成器—为Iterables提供更高级别的抽象。 它们还提供了新的控制流,可以解决诸如回调地狱之类的问题,并提供诸如Async/Await类的构建块。

Async/Await — provides higher level abstraction to Generators in order to specifically solving callback-hell issue.

Async / Await —为Generators提供更高级别的抽象,以便专门解决回调地狱问题。

Async Iterators — a brand-new 2018 feature to help with looping over an array of async functions to get the result of each async function just like in a normal loop.

异步迭代器 —一项2018年新增功能,可帮助循环访问一系列异步函数,以像正常循环一样获取每个异步函数的结果。

That’s pretty much it!

差不多了!

进一步阅读 (Further reading)

ECMAScript 2015+ (ECMAScript 2015+)

  1. Here are examples of everything new in ECMAScript 2016, 2017 and 2018

    以下是ECMAScript 2016、2017和2018中所有新增功能的示例

  2. Check out these useful ECMAScript 2015 (ES6) tips and tricks

    查看这些有用的ECMAScript 2015(ES6)提示和技巧

  3. 5 JavaScript “Bad” Parts That Are Fixed In ES6

    ES6中修复的5个JavaScript“不良”部分

  4. Is “Class” In ES6 The New “Bad” Part?

    ES6中的“类”是新的“不良”部分吗?

My other posts can be found here.

我的其他帖子可以在这里找到。

如果这有用,请单击拍手? 请点击以下几次以显示您的支持! ⬇⬇⬇ (If this was useful, please click the clap ? button down below a few times to show your support! ⬇⬇⬇)

翻译自: https://www.freecodecamp.org/news/some-of-javascripts-most-useful-features-can-be-tricky-let-me-explain-them-4003d7bbed32/

javascript迭代器

javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...相关推荐

  1. 同步等待 异步等待_异步/等待与承诺互操作性

    同步等待 异步等待 Usually, when discussing Promises and async/await syntax, people frame it as an "eith ...

  2. 同步等待 异步等待_异步/等待和承诺的解释

    同步等待 异步等待 The async / await operators make it easier to implement many async Promises. They also all ...

  3. ES6补充-异步与等待、符号、迭代器、代理以及生成器

    目录 异步与等待 async 异步 await 等待 Symbol 符号 迭代器 生成器 proxy 代理 异步与等待 async 异步 async作为一个关键字放到函数前面,用于表示函数是一个异步函 ...

  4. python生成器单线程_【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  5. JavaScript —从回调到异步/等待

    JavaScript is synchronous. This means that it will execute your code block by order after hoisting. ...

  6. python生成器和装饰器_python三大法器:生成器、装饰器、迭代器

    迭代器 迭代的概念 使用for循环遍历取值的过程叫做迭代,比如:使用for循环遍历列表获取值的过程 使用for循环遍历取值的对象叫做可迭代对象, 比如:列表.元组.字典.集合.range.字符串 判断 ...

  7. python 生成器装饰器_4.python迭代器生成器装饰器

    基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...

  8. python生成器yield原理_Python的迭代器和生成器 使用实例及yield的使用

    <派森>(Python)3.13 win32 英文安装版 类型:编程工具大小:21M语言:英文 评分:8.7 标签: 立即下载 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素 ...

  9. python生成器与迭代器的区别_python生成器和迭代器的区别

    匿名用户 1级 2016-10-13 回答 迭代器和生成器都是Python中特有的概念,迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个可迭代的对象必须是定义 ...

最新文章

  1. 设计模式(结构型模式)——享元模式(Flyweight)
  2. U盘安装Ubuntu三步走
  3. 风机桨叶故障诊断(六) 利用自编码器进行特征学习
  4. 十年云计算大爆发,微软正在摧毁其它竞争对手
  5. 使用Qt Creator 2.60编写C/C++程序
  6. 开源 协作工具_使用HackMD在开源项目上进行协作
  7. SCOM2007R2上监控TMG之部署Agent
  8. java中jq转移符,使用StringEscapeUtils对Java中特殊字符进行转义和反转义
  9. PS2手柄通讯协议解析---附资料和源码
  10. php获得当月的节假日函数(包含周末,年度节假日)
  11. Django cache redis 最全介绍
  12. 敏捷技术和管理方法思考列表---长期维护
  13. JS判断字符串是否含有某个值
  14. 对VR来说, 眼球追踪技术在里面到底是一个什么角色?
  15. 《十周成为数据分析师》笔记——业务线 第八节 常见互联网业务的数据分析报告的制作及用户分层模型
  16. 关于mysql中5位数字转化为日期格式的问题
  17. MySQL 生成随机数字、字符串、日期、验证码以及 UUID
  18. 我爱计算机:张俊林专访
  19. C++实现四舍五入的几种方法
  20. vb6.0发送邮件 html,VB6.0调用jmail发送邮件

热门文章

  1. C语言——冒泡法排序应用
  2. PHP连接数据库并创建一个表
  3. Xcode快捷键及代码块
  4. python之网络爬虫
  5. Angular开山篇
  6. 中国电信换将 三家运营商未来将如何争战
  7. 如何在centos安装python-mysql
  8. linux中的一些命令的想法
  9. tar、gzip、gunzip、bzip2、zip、unzip
  10. 接口学习笔记(2009.11.24)