javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...
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.
因此,在本文中,我将介绍symbols
, global symbols
, iterators
, iterables
iterators
, generators
, async/await
和async 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?
现在,如果我们添加另一个属性,说newProperty
到myObject
,如果你运行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(<ke
y>). This takes a “key” (string) to create a Symbol. And if a symbol with th
at key already exists, it simply returns the old symbol! So it behaves like a singleton if we use the Symb
ol.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
,但它不知道(或忽略) prop3
和prop4
因为他们是符号。
Below is another example where Object.keys
and Object.getOwnPropertyNames
are ignoring property names that are Symbols.
下面是另一个示例,其中Object.keys
和Object.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.search
和String.prototype.replace
中。
Some examples of these symbols are: Symbol.match
, Symbol.replace
, Symbol.search
, Symbol.iterator
and Symbol.split
.
这些符号的一些示例是: Symbol.match
, Symbol.replace
, Symbol.search
, Symbol.iterator
和Symbol.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))
Parse
‘rajarao’.search(‘rao’);
解析
'rajarao'.search('rao');
Convert “rajarao” into String Object
new String(“rajarao”)
将“ rajarao”转换为字符串对象
new String(“rajarao”)
Convert “rao” into RegExp object
new Regexp(“rao”)
将“ rao”转换成
new Regexp(“rao”)
RegExp对象new Regexp(“rao”)
Call
search
method of “rajarao” String object.调用“ rajarao”字符串对象的
search
方法。search
method internally callsSymbol.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")
"rao"[Symbol.search]("rajarao")
returns index result as4
tosearch
function and finally,search
returns4
back to our code."rao"[Symbol.search]("rajarao")
将索引结果作为4
返回到search
函数,最后,search
将4
返回到我们的代码。
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))
Parse
‘barsoap’.search(soapObj);
解析
'barsoap'.search(soapObj);
Convert “barsoap” into String Object
new String(“barsoap”)
将“ barsoap”转换为字符串对象
new String(“barsoap”)
Since
soapObj
is already an object, don’t do any conversion由于
soapObj
已经是一个对象,所以请勿进行任何转换Call
search
method of “barsoap” String object.调用“ barsoap”字符串对象的
search
方法。search
method internally callsSymbol.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")
soapObj[Symbol.search]("barsoap")
returns the index result asFOUND
tosearch
function and finally,search
returnsFOUND
back to our code.soapObj[Symbol.search]("barsoap")
将索引结果作为FOUND
返回到search
函数,最后,search
将FOUND
返回到我们的代码。
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:
规则是:
- The main object/class should store some data.主要对象/类应存储一些数据。
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实施特定方法。This
symbol.iterator
method must return another object — an “iterator” object.此
symbol.iterator
方法必须返回另一个对象-“ iterator”对象。This “iterator” object must have a method called the
next
method.该“迭代器”对象必须具有称为
next
方法的方法。The
next
method should have access to the data stored in rule #1.next
方法应该可以访问规则1中存储的数据。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.itera
tor]() to get the iterator (like allUsersIt
erator ) 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:
主要有两个原因:
- provide higher-level abstraction to iterables为可迭代对象提供更高级别的抽象
- 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:
以下是有关生成器的一些要点:
Generator methods have a new
*<myGenerat
or> syntax inside a class, and Generator functions have the syntax function * myGenerat
or(){}.生成器方法在类内部具有新的
*<myGenerat
或>语法,并且生成器函数具有syntax function * myGenerat
或(){}。Calling generators
myGenerator()
returns agenerator
object that also implements theiterator
protocol (rules), so we can use this as aniterator
return value out-of-the-box.调用generators
myGenerator()
返回一个generator
对象,该对象也实现了iterator
协议(规则),因此我们可以将其用作现成的iterator
返回值。Generators use a special
yield
statement to return data.生成器使用特殊的
yield
语句返回数据。yield
statements keep track of previous calls and simply continue from where it left off.yield
语句跟踪先前的调用,并从中断处继续。If you use
yield
inside a loop, it’ll only execute once each time we call thenext()
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
方法外,生成器对象还具有诸如throw
和return
之类的方法! 但是出于实际目的,我们可以将返回的对象用作“迭代器”。
原因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
(存储函数的state
和return
值),并且还可以在产生点处获取其他输入值。
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:
生成器和异步/等待之间的区别是:
async/await uses
await
instead ofyield
.async / await使用
await
而不是yield
。await
only works with Promises.await
仅适用于Promises。Instead of
function*
, it uses theasync 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
函数正在调用两个异步函数getUser
和getBankBalance
。 我们可以按承诺来做到这一点,但是使用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)
Iterator object' s
next()
method returns value like{value: ‘some val’, done: false}
迭代器对象的
next()
方法返回类似{value: 'some val', done: false}
Usage :
iterator.next() //{value: ‘some val’, done: false}
用法:
iterator.next() //{value: 'some val', done: false}
异步迭代器对象 (Async Iterator object)
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}
Usage:
iterator.next().then(({ value, done })=> {//{value: ‘some val’, done: fals
e}}用法:
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.keys
和for-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+)
Here are examples of everything new in ECMAScript 2016, 2017 and 2018
以下是ECMAScript 2016、2017和2018中所有新增功能的示例
Check out these useful ECMAScript 2015 (ES6) tips and tricks
查看这些有用的ECMAScript 2015(ES6)提示和技巧
5 JavaScript “Bad” Parts That Are Fixed In ES6
ES6中修复的5个JavaScript“不良”部分
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符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...相关推荐
- 同步等待 异步等待_异步/等待与承诺互操作性
同步等待 异步等待 Usually, when discussing Promises and async/await syntax, people frame it as an "eith ...
- 同步等待 异步等待_异步/等待和承诺的解释
同步等待 异步等待 The async / await operators make it easier to implement many async Promises. They also all ...
- ES6补充-异步与等待、符号、迭代器、代理以及生成器
目录 异步与等待 async 异步 await 等待 Symbol 符号 迭代器 生成器 proxy 代理 异步与等待 async 异步 async作为一个关键字放到函数前面,用于表示函数是一个异步函 ...
- python生成器单线程_【Python】迭代器、生成器、yield单线程异步并发实现详解
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
- JavaScript —从回调到异步/等待
JavaScript is synchronous. This means that it will execute your code block by order after hoisting. ...
- python生成器和装饰器_python三大法器:生成器、装饰器、迭代器
迭代器 迭代的概念 使用for循环遍历取值的过程叫做迭代,比如:使用for循环遍历列表获取值的过程 使用for循环遍历取值的对象叫做可迭代对象, 比如:列表.元组.字典.集合.range.字符串 判断 ...
- python 生成器装饰器_4.python迭代器生成器装饰器
基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...
- python生成器yield原理_Python的迭代器和生成器 使用实例及yield的使用
<派森>(Python)3.13 win32 英文安装版 类型:编程工具大小:21M语言:英文 评分:8.7 标签: 立即下载 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素 ...
- python生成器与迭代器的区别_python生成器和迭代器的区别
匿名用户 1级 2016-10-13 回答 迭代器和生成器都是Python中特有的概念,迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个可迭代的对象必须是定义 ...
最新文章
- 设计模式(结构型模式)——享元模式(Flyweight)
- U盘安装Ubuntu三步走
- 风机桨叶故障诊断(六) 利用自编码器进行特征学习
- 十年云计算大爆发,微软正在摧毁其它竞争对手
- 使用Qt Creator 2.60编写C/C++程序
- 开源 协作工具_使用HackMD在开源项目上进行协作
- SCOM2007R2上监控TMG之部署Agent
- java中jq转移符,使用StringEscapeUtils对Java中特殊字符进行转义和反转义
- PS2手柄通讯协议解析---附资料和源码
- php获得当月的节假日函数(包含周末,年度节假日)
- Django cache redis 最全介绍
- 敏捷技术和管理方法思考列表---长期维护
- JS判断字符串是否含有某个值
- 对VR来说, 眼球追踪技术在里面到底是一个什么角色?
- 《十周成为数据分析师》笔记——业务线 第八节 常见互联网业务的数据分析报告的制作及用户分层模型
- 关于mysql中5位数字转化为日期格式的问题
- MySQL 生成随机数字、字符串、日期、验证码以及 UUID
- 我爱计算机:张俊林专访
- C++实现四舍五入的几种方法
- vb6.0发送邮件 html,VB6.0调用jmail发送邮件