esma标准
In ECMAScript 2015, generators were introduced to the JavaScript language. A generator is a process that can be paused and resumed and can yield multiple values. A generator in JavaScript consists of a generator function, which returns an iterable Generator
object.
在ECMAScript 2015中 , 生成器被引入JavaScript语言。 生成器是可以暂停和恢复并可以产生多个值的过程。 JavaScript中的生成器包含一个生成器函数 ,该函数返回一个可迭代的Generator
对象。
In this article, we’ll cover how to create generator functions, how to iterate over Generator
objects, the difference between yield
and return
inside a generator, and other aspects of working with generators.
在本文中,我们将介绍如何创建生成器函数,如何迭代Generator
对象, Generator
内部yield
和return
之间的差异以及使用生成器的其他方面。
发电机功能 (Generator Functions)
A generator function is a function that returns a Generator
object, and is defined by the function
keyword followed by an asterisk (*
), as shown in the following:
生成器函数是一个返回Generator
对象的函数,由function
关键字定义,后跟一个星号( *
),如下所示:
// Generator function declaration
function* generatorFunction() {}
Occasionally, you will see the asterisk next to the function name, as opposed to the function keyword, such as function *generatorFunction()
. This works the same, but function*
is a more widely accepted syntax.
有时,您会在函数名称旁边看到星号,而不是像function *generatorFunction()
这样的function关键字。 它的工作原理相同,但是function*
是更广泛接受的语法。
Generator functions can also be defined in an expression, like regular functions:
生成器函数也可以在表达式中定义,例如常规函数 :
// Generator function expression
const generatorFunction = function* () {}
Generators can even be the methods of an object or class:
// Generator as the method of an object
const generatorObj = {
*generatorMethod() {},
}// Generator as the method of a class
class GeneratorClass {
*generatorMethod() {}
}
The examples throughout this article will use the generator function declaration syntax.
本文中的所有示例将使用生成器函数声明语法。
Note: Unlike regular functions, generators cannot be constructed with the
new
keyword, nor can they be used in conjunction with arrow functions.注意 :与常规函数不同,生成器不能使用
new
关键字 构造 ,也不能与 箭头函数 结合使用 。
Now that you know how to declare generator functions, lets look at the iterable Generator
objects that they return.
现在您知道如何声明生成器函数,让我们看一下它们返回的可迭代Generator
对象。
生成器对象 (Generator Objects)
Traditionally, functions in JavaScript run to completion, and calling a function will return a value when it arrives at the return
keyword. If the return
keyword is omitted, a function will implicitly return undefined
.
传统上,JavaScript中的函数会运行到完成状态,调用函数会在到达return
关键字时返回一个值。 如果省略return
关键字,则函数将隐式返回undefined
。
In the following code, for example, we declare a sum()
function that returns a value that is the sum of two integer arguments:
例如,在下面的代码中,我们声明一个sum()
函数,该函数返回一个值为两个整数参数之和的值:
// A regular function that sums two values
function sum(a, b) {
return a + b
}
Calling the function returns a value that is the sum of the arguments:
调用该函数将返回一个值,该值是参数的总和:
const value = sum(5, 6) // 11
A generator function, however, does not return a value immediately, and instead returns an iterable Generator
object. In the following example, we declare a function and give it a single return value, like a standard function:
但是,生成器函数不会立即返回值,而是返回可迭代的Generator
对象。 在下面的示例中,我们声明一个函数并给它一个返回值,就像标准函数一样:
// Declare a generator function with a single return value
function* generatorFunction() {
return 'Hello, Generator!'
}
When we invoke the generator function, it will return the Generator
object, which we can assign to a variable:
当我们调用generator函数时,它将返回Generator
对象,我们可以将其分配给变量:
// Assign the Generator object to generator
const generator = generatorFunction()
If this were a regular function, we would expect generator
to give us the string returned in the function. However, what we actually get is an object in a suspended
state. Calling generator
will therefore give output similar to the following:
如果这是一个常规函数,则我们希望generator
为我们提供函数中返回的字符串。 但是,我们实际上得到的是处于suspended
状态的对象。 因此,调用generator
将产生类似于以下内容的输出:
generatorFunction {<suspended>}
__proto__: Generator
[[GeneratorLocation]]: VM272:1
[[GeneratorStatus]]: "suspended"
[[GeneratorFunction]]: ƒ* generatorFunction()
[[GeneratorReceiver]]: Window
[[Scopes]]: Scopes[3]
The Generator
object returned by the function is an iterator. An iterator is an object that has a next()
method available, which is used for iterating through a sequence of values. The next()
method returns an object with value
and done
properties. value
represent the returned value, and done
indicates whether the iterator has run through all its values or not.
该函数返回的Generator
对象是一个迭代器 。 迭代器是一个具有next()
方法可用的对象,该方法用于遍历一系列值。 next()
方法返回具有value
和done
属性的对象。 value
表示返回的值, done
表示迭代器是否已遍历其所有值。
Knowing this, let’s call next()
on our generator
and get the current value and state of the iterator:
知道这一点后,让我们在generator
上调用next()
并获取迭代器的当前值和状态:
// Call the next method on the Generator object
generator.next()
This will give the following output:
这将给出以下输出:
{value: "Hello, Generator!", done: true}
The value returned from calling next()
is Hello, Generator!
, and the state of done
is true
, because this value came from a return
that closed out the iterator. Since the iterator is done, the generator function's status will change from suspended
to closed
. Calling generator
again will give the following:
调用next()
返回的值是Hello, Generator!
和状态done
是true
,因为这个数值从传来return
是收出迭代器。 由于迭代器已完成,因此生成器功能的状态将从“ suspended
变为“ closed
。 再次调用generator
将给出以下信息:
generatorFunction {<closed>}
As of right now, we’ve only demonstrated how a generator function can be a more complex way to get the return
value of a function. But generator functions also have unique features that distinguish them from normal functions. In the next section, we'll learn about the yield
operator and see how a generator can pause and resume execution.
到目前为止,我们仅演示了生成器函数如何成为获取函数return
值的更复杂方法。 但是生成器功能还具有独特的功能,可以将它们与正常功能区分开。 在下一节中,我们将了解yield
运算符,并了解生成器如何暂停和恢复执行。
yield
算子 (yield
Operators)
Generators introduce a new keyword to JavaScript: yield
. yield
can pause a generator function and return the value that follows yield
, providing a lightweight way to iterate through values.
生成器为JavaScript引入了一个新关键字: yield
。 yield
可以暂停生成器函数并返回yield
后面的值,从而提供了一种轻量级的方法来遍历值。
In this example, we’ll pause the generator function three times with different values, and return a value at the end. Then we will assign our Generator
object to the generator
variable.
在此示例中,我们将使用不同的值暂停生成器函数三次,然后在最后返回一个值。 然后,我们将Generator
对象分配给generator
变量。
// Create a generator function with multiple yields
function* generatorFunction() {
yield 'Neo'
yield 'Morpheus'
yield 'Trinity' return 'The Oracle'
}const generator = generatorFunction()
Now, when we call next()
on the generator function, it will pause every time it encounters yield
. done
will be set to false
after each yield
, indicating that the generator has not finished. Once it encounters a return
, or there are no more yield
s encountered in the function, done
will flip to true
, and the generator will be finished.
现在,当我们在generator函数上调用next()
时,它将在每次遇到yield
时暂停。 每个yield
,将done
设置为false
,指示生成器尚未完成。 一旦遇到return
,或者函数中不再遇到yield
,则done
将翻转为true
,并且生成器将完成。
Use the next()
method four times in a row:
连续四次使用next()
方法:
// Call next four times
generator.next()
generator.next()
generator.next()
generator.next()
These will give the following four lines of output in order:
这些将按顺序给出以下四行输出:
{value: "Neo", done: false}
{value: "Morpheus", done: false}
{value: "Trinity", done: false}
{value: "The Oracle", done: true}
Note that a generator does not require a return
; if omitted, the last iteration will return {value: undefined, done: true}
, as will any subsequent calls to next()
after a generator has completed.
注意,生成器不需要return
; 如果省略,则最后一次迭代将返回{value: undefined, done: true}
,以及生成器完成后对next()
任何后续调用。
遍历生成器 (Iterating Over a Generator)
Using the next()
method, we manually iterated through the Generator
object, receiving all the value
and done
properties of the full object. However, just like Array
, Map
, and Set
, a Generator
follows the iteration protocol, and can be iterated through with for...of
:
使用next()
方法,我们手动遍历Generator
对象,接收完整对象的所有value
和done
属性。 但是,就像Array
, Map
和 Set
, Generator
遵循迭代协议 ,可以使用for...of
进行迭代:
// Iterate over Generator object
for (const value of generator) {
console.log(value)
}
This will return the following:
这将返回以下内容:
Neo
Morpheus
Trinity
The spread operator can also be used to assign the values of a Generator
to an array.
扩展运算符还可以用于将Generator
的值分配给数组。
// Create an array from the values of a Generator object
const values = [...generator]console.log(values)
This will give the following array:
这将给出以下数组:
(3) ["Neo", "Morpheus", "Trinity"]
Both spread and for...of
will not factor the return
into the values (in this case, it would have been 'The Oracle'
).
传播和for...of
都不会考虑return
值的情况(在这种情况下,它将是'The Oracle'
)。
Note: While both of these methods are effective for working with finite generators, if a generator is dealing with an infinite data stream, it won’t be possible to use spread or
for...of
directly without creating an infinite loop.注意 :虽然这两种方法对于使用有限生成器都是有效的,但是如果生成器正在处理无限数据流,则
for...of
不创建无限循环的情况下 将无法直接使用spread或for...of
。
关闭发电机 (Closing a Generator)
As we’ve seen, a generator can have its done
property set to true
and its status set to closed
by iterating through all its values. There are two additional ways to immediately cancel a generator: with the return()
method, and with the throw()
method.
如我们所见,生成器可以通过迭代所有值将其done
属性设置为true
并将其状态设置为closed
。 有两种其他方法可以立即取消生成器:使用return()
方法和throw()
方法。
With return()
, the generator can be terminated at any point, just as if a return
statement had been in the function body. You can pass an argument into return()
, or leave it blank for an undefined value.
使用return()
,可以在任何时候终止生成器,就像在函数体中使用return
语句一样。 您可以将参数传递给return()
,也可以将其保留为空白以获取未定义的值。
To demonstrate return()
, we'll create a generator with a few yield
values but no return
in the function definition:
为了演示return()
,我们将创建一个生成器,该生成器具有一些yield
值,但函数定义中没有return
:
function* generatorFunction() {
yield 'Neo'
yield 'Morpheus'
yield 'Trinity'
}const generator = generatorFunction()
The first next()
will give us 'Neo'
, with done
set to false
. If we invoke a return()
method on the Generator
object right after that, we'll now get the passed value and done
set to true
. Any additional call to next()
will give the default completed generator response with an undefined value.
第一个next()
将为我们提供'Neo'
,将done
设置为false
。 如果我们调用return()
的方法Generator
之后客体的权利,我们现在会得到传递价值和done
设置为true
。 对next()
任何其他调用都将为默认的完整生成器响应提供一个未定义的值。
To demonstrate this, run the following three methods on generator
:
为了证明这一点,请在generator
上运行以下三种方法:
generator.next()
generator.return('There is no spoon!')
generator.next()
This will give the three following results:
这将给出以下三个结果:
{value: "Neo", done: false}
{value: "There is no spoon!", done: true}
{value: undefined, done: true}
The return()
method forced the Generator
object to complete and to ignore any other yield
keywords. This is particularly useful in asynchronous programming when you need to make functions cancelable, such as interrupting a web request when a user wants to perform a different action, as it is not possible to directly cancel a Promise.
return()
方法强制Generator
对象完成操作,并忽略任何其他yield
关键字。 当您需要取消功能时,这在异步编程中特别有用,例如当用户想要执行其他操作时中断Web请求,因为不可能直接取消Promise。
If the body of a generator function has a way to catch and deal with errors, you can use the throw()
method to throw an error into the generator. This starts up the generator, throws the error in, and terminates the generator.
如果生成器函数的主体具有捕获和处理错误的方法,则可以使用throw()
方法将错误抛出到生成器中。 这将启动生成器,引发错误,并终止生成器。
To demonstrate this, we will put a try...catch
inside the generator function body and log an error if one is found:
为了证明这一点,我们将try...catch
放在生成器函数体内,如果发现错误,则记录错误:
// Define a generator function
function* generatorFunction() {
try {
yield 'Neo'
yield 'Morpheus'
} catch (error) {
console.log(error)
}
}// Invoke the generator and throw an error
const generator = generatorFunction()
Now, we will run the next()
method, followed by throw()
:
现在,我们将运行next()
方法,然后运行throw()
:
generator.next()
generator.throw(new Error('Agent Smith!'))
This will give the following output:
这将给出以下输出:
{value: "Neo", done: false}
Error: Agent Smith!
{value: undefined, done: true}
Using throw()
, we injected an error into the generator, which was caught by the try...catch
and logged to the console.
使用throw()
,我们向生成器注入了一个错误,该错误被try...catch
并记录到控制台。
生成器对象的方法和状态 (Generator Object Methods and States)
The following table shows a list of methods that can be used on Generator
objects:
下表显示了可以在Generator
对象上使用的方法的列表:
MethodDescriptionnext()
Returns the next value in a generatorreturn()
Returns a value in a generator and finishes the generatorthrow()
Throws an error and finishes the generator
MethodDescription next()
返回生成器中的下一个值return()
返回生成器中的值并完成生成器throw()
引发错误并完成生成器
The next table lists the possible states of a Generator
object:
下表列出了Generator
对象的可能状态:
StatusDescriptionsuspended
Generator has halted execution but has not terminatedclosed
Generator has terminated by either encountering an error, returning, or iterating through all values
StatusDescription suspended
Generator已停止执行,但尚未终止closed
Generator通过遇到错误,返回或遍历所有值而终止
yield
委托 (yield
Delegation)
In addition to the regular yield
operator, generators can also use the yield*
expression to delegate further values to another generator. When the yield*
is encountered within a generator, it will go inside the delegated generator and begin iterating through all the yield
s until that generator is closed. This can be used to separate different generator functions to semantically organize your code, while still having all their yield
s be iterable in the right order.
除了常规的yield
运算符之外,生成器还可以使用yield*
表达式将其他值委托给另一个生成器。 当在生成器中遇到yield*
时,它将进入委托的生成器内部并开始遍历所有yield
直到该生成器关闭。 这可以用于分离不同的生成功能,语义组织代码,同时还具有所有的yield
S为迭代以正确的顺序。
To demonstrate, we can create two generator functions, one of which will yield*
operate on the other:
为了演示,我们可以创建两个生成器函数,其中一个将对另一个函数yield*
。
// Generator function that will be delegated to
function* delegate() {
yield 3
yield 4
}// Outer generator function
function* begin() {
yield 1
yield 2
yield* delegate()
}
Next, let’s iterate through the begin()
generator function:
接下来,让我们遍历begin()
生成器函数:
// Iterate through the outer generator
const generator = begin()for (const value of generator) {
console.log(value)
}
This will give the following values in the order they are generated:
这将按生成顺序给出以下值:
1
2
3
4
The outer generator yielded the values 1
and 2
, then delegated to the other generator with yield*
, which returned 3
and 4
.
外部生成器产生值1
和2
,然后将其委托给另一个带有yield*
生成器,返回3
和4
。
yield*
can also delegate to any object that is iterable, such as an Array or a Map. Yield delegation can be helpful in organizing code, since any function within a generator that wanted to use yield
would also have to be a generator.
yield*
还可以委托给任何可迭代的对象,例如Array或Map。 产量委托对于组织代码很有帮助,因为要使用yield
的生成器中的任何函数也必须是生成器。
无限数据流 (Infinite Data Streams)
One of the useful aspects of generators is the ability to work with infinite data streams and collections. This can be demonstrated by creating an infinite loop inside a generator function that increments a number by one.
生成器的有用方面之一是能够处理无限数据流和集合。 这可以通过在生成器函数内创建一个无限循环来证明,该循环将数字加一。
In the following code block, we define this generator function and then initiate the generator:
在下面的代码块中,我们定义此生成器函数,然后启动生成器:
// Define a generator function that increments by one
function* incrementer() {
let i = 0 while (true) {
yield i++
}
}// Initiate the generator
const counter = incrementer()
Now, iterate through the values using next()
:
现在,使用next()
遍历值:
// Iterate through the values
counter.next()
counter.next()
counter.next()
counter.next()
This will give the following output:
这将给出以下输出:
{value: 0, done: false}
{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
The function returns successive values in the infinite loop while the done
property remains false
, ensuring that it will not finish.
该函数将在infinite循环中返回连续的值,而done
属性仍为false
,以确保它不会完成。
With generators, you don’t have to worry about creating an infinite loop, because you can halt and resume execution at will. However, you still have to have caution with how you invoke the generator. If you use spread or for...of
on an infinite data stream, you will still be iterating over an infinite loop all at once, which will cause the environment to crash.
使用生成器,您不必担心创建无限循环,因为您可以随意停止并恢复执行。 但是,您仍然必须谨慎对待如何调用生成器。 如果在无限数据流上使用spread或for...of
,则仍将一次遍历无限循环,这将导致环境崩溃。
For a more complex example of an infinite data stream, we can create a Fibonacci generator function. The Fibonacci sequence, which continuously adds the two previous values together, can be written using an infinite loop within a generator as follows:
对于无限数据流的更复杂的示例,我们可以创建一个Fibonacci生成器函数。 斐波那契数列将两个先前的值连续加在一起,可以使用生成器中的无限循环来编写,如下所示:
// Create a fibonacci generator function
function* fibonacci() {
let prev = 0
let next = 1 yield prev
yield next // Add previous and next values and yield them forever
while (true) {
const newVal = next + prev yield newVal prev = next
next = newVal
}
}
To test this out, we can loop through a finite number and print the Fibonacci sequence to the console.
为了测试这一点,我们可以遍历一个有限的数并将Fibonacci序列打印到控制台。
// Print the first 10 values of fibonacci
const fib = fibonacci()for (let i = 0; i < 10; i++) {
console.log(fib.next().value)
}
This will give the following:
这将给出以下内容:
0
1
1
2
3
5
8
13
21
34
The ability to work with infinite data sets is one part of what makes generators so powerful. This can be useful for examples like implementing infinite scroll on the frontend of a web application, or operating on sound wave data.
处理无限数据集的能力是使生成器如此强大的原因之一。 这对于例如在Web应用程序的前端上实现无限滚动或对声波数据进行操作的示例很有用。
在生成器中传递值 (Passing Values in Generators)
Throughout this article, we’ve used generators as iterators, and we’ve yielded values in each iteration. In addition to producing values, generators can also consume values from next()
. In this case, yield
will contain a value.
在整个本文中,我们将生成器用作迭代器,并且在每次迭代中都产生了值。 除了产生值之外,生成器还可以使用next()
值。 在这种情况下, yield
将包含一个值。
It’s important to note that the first next()
that is called will not pass a value, but will only start the generator. To demonstrate this, we can log the value of yield
and call next()
a few times with some values.
重要的是要注意,第一个next()
不会传递值,而只会启动生成器。 为了证明这一点,我们可以记录yield
的值,并使用某些值多次调用next()
。
function* generatorFunction() {
console.log(yield)
console.log(yield) return 'The end'
}const generator = generatorFunction()generator.next()
generator.next(100)
generator.next(200)
This will give the following output:
这将给出以下输出:
100
200
{value: "The end", done: true}
It is also possible to seed the generator with an initial value. In the following example, we’ll make a for
loop and pass each value into the next()
method, but pass an argument to the inital function as well:
也可以使用初始值为生成器提供种子。 在下面的示例中,我们将进行一个for
循环,并将每个值传递给next()
方法,但还将一个参数传递给inital函数:
function* generatorFunction(value) {
while (true) {
value = yield value * 10
}
}// Initiate a generator and seed it with an initial value
const generator = generatorFunction(0)for (let i = 0; i < 5; i++) {
console.log(generator.next(i).value)
}
We’ll retrieve the value from next()
and yield a new value to the next iteration, which is the previous value times ten. This will give the following:
我们将从next()
检索值,并为下一次迭代生成一个新值,该值是前一个值乘以10。 这将给出以下内容:
0
10
20
30
40
Another way to deal with starting up a generator is to wrap the generator in a function that will always call next()
once before doing anything else.
处理生成器的另一种方法是将生成器包装在一个函数中,该函数将在执行其他任何操作之前始终调用next()
一次。
与发电机async
/ await
(async
/await
with Generators)
An asynchronous function is a type of function available in ES6+ JavaScript that makes working with asynchronous data simpler and easier to understand by making it appear synchronous. Generators have a more extensive array of capabilities than asynchronous functions, but are capable of replicating similar behavior. Implementing asynchronous programming in this way can increase the flexibility of your code.
异步函数是ES6 + JavaScript中提供的一种函数,通过使异步数据看起来像同步的,它使处理异步数据更加简单和容易理解。 生成器比异步函数具有更多的功能,但是能够复制相似的行为。 以这种方式实现异步编程可以提高代码的灵活性。
In this section, we will demonstrate an example of reproducing async
/await
with generators.
在本节中,我们将演示一个使用生成器再现async
/ await
的示例。
Let’s build an asynchronous function that uses the Fetch API to get data from the JSONPlaceholder API (which provides example JSON data for testing purposes) and logs the response to the console.
让我们构建一个异步函数, 该函数使用Fetch API从JSONPlaceholder API获取数据(该API提供示例JSON数据用于测试)并将响应记录到控制台。
Start out by defining an asynchronous function called getUsers
that fetches data from the API and returns an array of objects, then call getUsers
:
首先定义一个名为getUsers
的异步函数,该函数从API提取数据并返回对象数组,然后调用getUsers
:
const getUsers = async function () {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
const json = await response.json() return json
}// Call the getUsers function and log the response
getUsers().then((response) => console.log(response))
This will give the following JSON data:
这将提供以下JSON数据:
[ {id: 1, name: "Leanne Graham" ...},
{id: 2, name: "Ervin Howell" ...},
{id: 3, name": "Clementine Bauch" ...},
{id: 4, name: "Patricia Lebsack"...},
{id: 5, name: "Chelsey Dietrich"...},
{id: 6, name: "Mrs. Dennis Schulist"...},
{id: 7, name: "Kurtis Weissnat"...},
{id: 8, name: "Nicholas Runolfsdottir V"...},
{id: 9, name: "Glenna Reichert"...},
{id: 10, name: "Clementina DuBuque"...}]
Using generators, we can create something almost identical that does not use the async
/await
keywords. Instead, it will use a new function we create, and yield
values instead of await
promises.
使用生成器,我们可以创建几乎不使用async
/ await
关键字的相同内容。 取而代之的是,它将使用我们创建的新函数,并yield
值而不是await
诺言。
In the following code block, we define a function called getUsers
that uses our new asyncAlt
function (which we will write later on) to mimic async
/await
.
在下面的代码块中,我们定义了一个名为getUsers
的函数,该函数使用新的asyncAlt
函数(稍后将进行编写)来模仿async
/ await
。
const getUsers = asyncAlt(function* () {
const response = yield fetch('https://jsonplaceholder.typicode.com/users')
const json = yield response.json() return json
})// Invoking the function
getUsers().then((response) => console.log(response))
As we can see, it looks almost identical to the async
/await
implementation, except that there is a generator function being passed in that yields values.
如我们所见,它看起来与async
/ await
实现几乎相同,除了其中传递了生成值的生成器函数外。
Now we can create an asyncAlt
function that resembles an asynchronous function. asyncAlt
has a generator function as a parameter, which is our function that yields the promises that fetch
returns. asyncAlt
returns a function itself, and resolves every promise it finds until the last one:
现在我们可以创建类似于异步函数的asyncAlt
函数。 asyncAlt
具有一个生成器函数作为参数,这是我们的函数,可产生fetch
返回的承诺。 asyncAlt
本身asyncAlt
返回一个函数,并解决找到的每个诺言,直到最后一个:
// Define a function named asyncAlt that takes a generator function as an argument
function asyncAlt(generatorFunction) {
// Return a function
return function () {
// Create and assign the generator object
const generator = generatorFunction() // Define a function that accepts the next iteration of the generator
function resolve(next) {
// If the generator is closed and there are no more values to yield,
// resolve the last value
if (next.done) {
return Promise.resolve(next.value)
} // If there are still values to yield, they are promises and
// must be resolved.
return Promise.resolve(next.value).then((response) => {
return resolve(generator.next(response))
})
} // Begin resolving promises
return resolve(generator.next())
}
}
This will give the same output as the async
/await
version:
这将提供与async
/ await
版本相同的输出:
[ {id: 1, name: "Leanne Graham" ...},
{id: 2, name: "Ervin Howell" ...},
{id: 3, name": "Clementine Bauch" ...},
{id: 4, name: "Patricia Lebsack"...},
{id: 5, name: "Chelsey Dietrich"...},
{id: 6, name: "Mrs. Dennis Schulist"...},
{id: 7, name: "Kurtis Weissnat"...},
{id: 8, name: "Nicholas Runolfsdottir V"...},
{id: 9, name: "Glenna Reichert"...},
{id: 10, name: "Clementina DuBuque"...}]
Note that this implementation is for demonstrating how generators can be used in place of async
/await
, and is not a production-ready design. It does not have error handling set up, nor does it have the ability to pass parameters into the yielded values. Though this method can add flexibility to your code, often async/await
will be a better choice, since it abstracts implementation details away and lets you focus on writing productive code.
请注意,此实现用于演示如何使用生成器代替async
/ await
,而不是可用于生产的设计。 它没有设置错误处理,也没有能力将参数传递给产生的值。 尽管此方法可以为您的代码增加灵活性,但通常async/await
将是一个更好的选择,因为它抽象了实现细节,使您专注于编写高效的代码。
结论 (Conclusion)
Generators are processes that can halt and resume execution. They are a powerful, versatile feature of JavaScript, although they are not commonly used. In this tutorial, we learned about generator functions and generator objects, methods available to generators, the yield
and yield*
operators, and using generators with finite and infinite data sets. We also explored one way to implement asynchronous code without nested callbacks or long promise chains
生成器是可以暂停并恢复执行的进程。 它们是JavaScript的强大功能,尽管并不常用。 在本教程中,我们了解了生成器函数和生成器对象,生成器可用的方法, yield
和yield*
运算符,以及如何使用具有有限和无限数据集的生成器。 我们还探索了一种无需嵌套回调或长承诺链即可实现异步代码的方法
翻译自: https://medium.com/swlh/understanding-generators-in-javascript-esma-script-fcca9eda19fa
esma标准