From 46053707cad427b59f1dceb2a98ec304842191c4 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sat, 14 Mar 2020 23:47:57 +0800 Subject: [PATCH 1/9] Update article.md --- 1-js/12-generators-iterators/1-generators/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index b1a7980ff7..8f09354348 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -1,4 +1,4 @@ -# Generators +# Generator 常规函数只会返回一个具体值(或者 `undefined`)。 From a95d1a0ea5310ad1018653aac7d2e96e6dd0d0f9 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 09:24:12 +0800 Subject: [PATCH 2/9] Update article.md --- .../1-generators/article.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 8f09354348..c0e0a573c6 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -1,12 +1,12 @@ # Generator -常规函数只会返回一个具体值(或者 `undefined`)。 +常规函数只会返回一个单一值(或者不返回任何值)。 -而 Generators 可以按需逐个生成(“yield”)多个值。它们与 [iterables](info:iterable) 配合使用,可以轻松创建数据流。 +而 Generator 可以按需一个接一个地返回("yield")多个值。它们可与 [iterable](info:iterable) 完美配合使用,从而可以轻松地创建数据流。 ## Generator 函数 -要创建 generator,我们需要一个特殊的语法结构:`function*`,即所谓的“generator 函数”。 +要创建一个 generator,我们需要一个特殊的语法结构:`function*`,即所谓的“generator 函数”。 它看起来像这样: @@ -18,25 +18,25 @@ function* generateSequence() { } ``` -“generator 函数”与常规函数的运行表现有所不同,当执行“generator 函数”时,它并不直接执行完**函数体**的代码,而是返回一个特殊的对象,即“generator 对象”,来管理执行流程。 +Generator 函数与常规函数的行为不同。在此类函数被调用时,它不会运行其代码。而是返回一个被称为 "generator object" 的特殊对象,来管理执行流程。 -来打印一下这种对象: +我们来看一个例子: -```js +```js run function* generateSequence() { yield 1; yield 2; return 3; } -// "generator function"(指 generateSequence()) 创建了一个 "generator 对象" +// "generator function" 创建了一个 "generator object" let generator = generateSequence(); *!* alert(generator); // [object Generator] */!* ``` -上面的代码中,**函数体**代码还没有开始执行: +到目前为止,上面这段代码中的 **函数体** 代码还没有开始执行: ![](generateSequence-1.svg) From aa7972cfd1d16a5472ab052e9aeadee7dc1bbaab Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 10:00:37 +0800 Subject: [PATCH 3/9] Update article.md --- .../1-generators/article.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index c0e0a573c6..eadfcb25b0 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -6,7 +6,7 @@ ## Generator 函数 -要创建一个 generator,我们需要一个特殊的语法结构:`function*`,即所谓的“generator 函数”。 +要创建一个 generator,我们需要一个特殊的语法结构:`function*`,即所谓的 "generator function"。 它看起来像这样: @@ -40,13 +40,13 @@ alert(generator); // [object Generator] ![](generateSequence-1.svg) -generator 对象的主要方法是 `next()`。被调用时,它会恢复上面的执行过程直到最近的 `yield ` 语句( `value` 可以省略,默认为 `undefined` )。然后代码再次暂停执行,并将值返回给外部代码。 +一个 generator 的主要方法就是 `next()`。当被调用时(译注:指 `next()` 方法),它会恢复上图所示的运行,执行直到最近的 `yield ` 语句(`value` 可以被省略,默认为 `undefined`)。然后函数执行暂停,并将产生的(yielded)值返回到外部代码。 -`next()` 调用结果总是一个包含两个属性的对象: -- `value`: “generator 函数”每次 **产出(yielded)** 的值。(译者注:yield翻译为产出,是为了配合 **生成器(generator)** 的语义。) -- `done`: `true` 表示“generator 函数”已经执行完成,否则为 `false`。 +`next()` 的结果始终是一个具有两个属性的对象: +- `value`: 产生的(yielded)的值。 +- `done`: 如果 generator 函数已执行完成则为 `true`,否则为 `false`。 -举个例子,下面我们创建一个 generator 并获取其第一个产出的值: +例如,我们可以创建一个 generator 并获取其第一个产生的(yielded)值: ```js run function* generateSequence() { @@ -64,11 +64,11 @@ let one = generator.next(); alert(JSON.stringify(one)); // {value: 1, done: false} ``` -截至目前,我们只获得了第一个值,函数体停在了第二行: +截至目前,我们只获得了第一个值,现在函数执行处在第二行: ![](generateSequence-2.svg) -再次调用 `generator.next()`。代码恢复执行并返回下一个 `yield` 的产出值: +让我们再次调用 `generator.next()`。代码恢复执行并返回下一个 `yield` 的值: ```js let two = generator.next(); @@ -78,7 +78,7 @@ alert(JSON.stringify(two)); // {value: 2, done: false} ![](generateSequence-3.svg) -如果我们第三次调用上面代码,代码将会执行到 `return` 语句,此时将会完成这个函数的执行: +如果我们第三次调用 `generator.next()`,代码将会执行到 `return` 语句,此时就完成这个函数的执行: ```js let three = generator.next(); @@ -88,21 +88,21 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} ![](generateSequence-4.svg) -我们通过 `done:true` 可以看出函数执行完成了,此时 `value:3` 作为函数执行的最终结果。 +现在 generator 执行完成。我们通过 `done:true` 可以看出来这一点,并且将 `value:3` 处理为最终结果。 -再调用 `generator.next()` 已经没有什么意义了。这将总是返回相同的对象:`{done: true}`。 +再对 `generator.next()` 进行新的调用不再有任何意义。如果我们这样做,它将返回相同的对象:`{done: true}`。 -```smart header="`function* f(…)` 或者 `function *f(…)`?" -这是一个小的书写习惯问题,两者的语法都是正确的。 +```smart header="`function* f(…)` 或 `function *f(…)`?" +这两种语法都是对的。 -但是通常首选第一种语法,因为星号 `*` 表示它是一个 generator 函数,它描述的是函数种类而不是名称,因此`*`应该和 `function` 关键字紧贴一起。 +但是通常更倾向于第一种语法,因为星号 `*` 表示它是一个 generator 函数,它描述的是函数种类而不是名称,因此 `*` 应该和 `function` 关键字紧贴一起。 ``` -## Generators 是可迭代的 +## Generator 是可迭代的 -看到 `next()` 方法,或许你都猜到了 generator 是 [可迭代](info:iterable) 的。(译者注:`next()` 是 iterator 的必要方法) +当你看到 `next()` 方法,或许你已经猜到了 generator 是 [可迭代(iterable)](info:iterable)的。(译注:`next()` 是 iterator 的必要方法) -我们可以通过 `for..of` 循环迭代所有值: +我们可以使用 `for..of` 循环遍历它所有的值: ```js run function* generateSequence() { @@ -114,15 +114,15 @@ function* generateSequence() { let generator = generateSequence(); for(let value of generator) { - alert(value); // 1, then 2 + alert(value); // 1,然后是 2 } ``` -`for ... of` 写法是不是比 `.next().value` 优雅多了? +`for..of` 写法是不是看起来比 `.next().value` 优雅多了? -……但是请注意:上面的迭代例子中,它先显示 `1`,然后是 `2`。它不会显示 `3`! +……但是请注意:上面这个例子会先显示 `1`,然后是 `2`,然后就没了。它不会显示 `3`! -这是因为当 `done: true` 时,for-of 循环会忽略最后一个 `value`。因此,如果我们想要通过 `for..of` 循环显示所有结果时,我们必须使用 `yield` 而不是 `return`: +这是因为当 `done: true` 时,`for..of` 循环会忽略最后一个 `value`。因此,如果我们想要通过 `for..of` 循环显示所有的结果,我们必须使用 `yield` 返回它们: ```js run function* generateSequence() { @@ -136,11 +136,11 @@ function* generateSequence() { let generator = generateSequence(); for(let value of generator) { - alert(value); // 1, then 2, then 3 + alert(value); // 1,然后是 2,然后是 3 } ``` -由于 generators 是可迭代的,我们可以充分发挥 ES6 中 iterator 的特性,例如:spread 操作 `...`: +因为 generator 是可迭代的,我们可以使用 iterator 的所有相关功能,例如:spread 语法 `...`: ```js run function* generateSequence() { @@ -154,7 +154,7 @@ let sequence = [0, ...generateSequence()]; alert(sequence); // 0, 1, 2, 3 ``` -在上面的代码中,`...generateSequence()` 将可迭代的“generator 对象”转换为了一个数组(关于 spread 操作可以参见相关章节 [](info:rest-parameters-spread-operator#spread-operator))。 +在上面这段代码中,`...generateSequence()` 将可迭代的“generator 对象”转换为了一个数组(关于 spread 操作可以参见相关章节 [](info:rest-parameters-spread-operator#spread-operator))。 ## 使用 generator 进行迭代 From 88d04d6b0d2f2a08419b6d0b862f0c045f957232 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 10:44:17 +0800 Subject: [PATCH 4/9] Update article.md --- .../1-generators/article.md | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index eadfcb25b0..621bc3dbe4 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -154,13 +154,13 @@ let sequence = [0, ...generateSequence()]; alert(sequence); // 0, 1, 2, 3 ``` -在上面这段代码中,`...generateSequence()` 将可迭代的“generator 对象”转换为了一个数组(关于 spread 操作可以参见相关章节 [](info:rest-parameters-spread-operator#spread-operator))。 +在上面这段代码中,`...generateSequence()` 将可迭代的 generator 对象转换为了一个数组(关于 spread 语法的更多细节请见 []info:rest-parameters-spread#spread-syntax))。 ## 使用 generator 进行迭代 -在前面章节,[](info:iterable) 我们创建了可迭代的 `range` 对象,它返回 `from..to` 的值。 +在前面的 [](info:iterable) 一章中,我们创建了一个可迭代的 `range` 对象,它返回 `from..to` 的值。 -现在,我们一起回忆下之前的代码: +现在,我们回忆一下代码: ```js run let range = { @@ -169,15 +169,15 @@ let range = { // for..of range 在一开始就调用一次这个方法 [Symbol.iterator]() { - // ……它返回 iterator 对象: - // 后续的操作中, for..of 将只针对这个 iterator 对象,通过不断的调用 next() 来获取下一个值 + // ...它返回可迭代对象(iterator): + // 后续的操作中,for..of 将只针对这个可迭代对象,要求它提供下一个值 return { current: this.from, last: this.to, - // for..of 在每次迭代的时候都会调用 next() + // for..of 循环在每次迭代时都会调用 next() next() { - // 必须返回特定结构的对象: {done:.., value :...} + // 它应该以对象 {done:.., value :...} 的形式返回值 if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { @@ -188,13 +188,13 @@ let range = { } }; -// 迭代整个 range 对象,返回从 `range.from` 到 `range.to` 范围的所有数字的数组。 +// 迭代整个 range 对象,返回从 `range.from` 到 `range.to` 范围的所有数字 alert([...range]); // 1,2,3,4,5 ``` -我们可以通过提供一个 generator 函数作为对象的 `Symbol.iterator` 来使任何对象可被迭代。 +我们可以通过提供一个 generator 函数作为 `Symbol.iterator`,来使用 generator 进行迭代: -以下是使用的另一种更紧凑的写法的 `range` 对象: +下面是一个相同的 `range`,但紧凑得多: ```js run let range = { @@ -211,11 +211,13 @@ let range = { alert( [...range] ); // 1,2,3,4,5 ``` -代码正常工作,因为 `range[Symbol.iterator]()` 现在返回一个 generator,而 generator 方法正是 `for..of` 所期望的: +之所以代码正常工作,是因为 `range[Symbol.iterator]()` 现在返回一个 generator,而 generator 方法正是 `for..of` 所期望的: - 它具有 `.next()` 方法 - 它以 `{value: ..., done: true/false}` 的形式返回值 -当然,这不是巧合,Generators 被添加到 JavaScript 语言中时也考虑了 iterators,以便更容易实现。 +当然,这不是巧合。 + +Generator 被添加到 JavaScript 语言中时也考虑了 iterators,以便更容易实现。 带有 generator 的 `range` 对象比的原始可迭代代码简洁得多,还保持了功能的一致。 From 6de126c907cb4ecd93ff4660896dfa7f26a1e941 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 12:35:14 +0800 Subject: [PATCH 5/9] Update article.md --- .../1-generators/article.md | 114 +++++++++--------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 621bc3dbe4..671b61eee2 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -215,23 +215,21 @@ alert( [...range] ); // 1,2,3,4,5 - 它具有 `.next()` 方法 - 它以 `{value: ..., done: true/false}` 的形式返回值 -当然,这不是巧合。 +当然,这不是巧合。Generator 被添加到 JavaScript 语言中是有对 iterator 的考量的,以便更容易地实现 iterator。 -Generator 被添加到 JavaScript 语言中时也考虑了 iterators,以便更容易实现。 +带有 generator 的变体比原来的 `range` 迭代代码简洁得多,并且保持了相同的功能。 -带有 generator 的 `range` 对象比的原始可迭代代码简洁得多,还保持了功能的一致。 +```smart header="Generator 可以永远产生值" +在上面的示例中,我们生成了有限序列,但是我们也可以创建一个生成无限序列的 generator,它可以一直 yield 值。例如,无序的伪随机数序列。 -```smart header="Generators 可以永远产生值" -在上面的例子中,我们生成了有限序列,但是我们也可以创建一个生成无限序列的 generator,它可以一直 yield 值。例如,无序的伪随机数序列。 - -这种情况下的 `for..of` generator 需要一个 `break`(或者 `return`)语句,否则循环将永远重复并挂起。 +这种情况下肯定需要在 generator 的 `for..of` 循环中添加一个 `break`(或者 `return`)。否则循环将永远重复下去并挂起。 ``` -## Generator 组合(composition) +## Generator 组合 -Generator 组合是 generator 的一个特殊功能,它可以显式地将 generator “嵌入”到一起。 +Generator 组合(composition)是 generator 的一个特殊功能,它允许透明地(transparently)将 generator 彼此“嵌入(embed)”到一起。 -如下,我们有个生成数字序列的函数: +例如,我们有一个生成数字序列的函数: ```js function* generateSequence(start, end) { @@ -239,18 +237,18 @@ function* generateSequence(start, end) { } ``` -接着,我们复用这个函数来生成更加复杂的包含三部分的序列: -- 第一部分为数字 `0..9`(ASCII 可显示字符代码为 48..57), -- 第二部分为大写字母字母 `A..Z`(ASCII 可显示字符代码为 65..90) -- 第三部分为小写字母 `a...z`(ASCII 可显示字符代码为 97..122) +现在,我们想重用它来生成一个更复杂的序列: +- 首先是数字 `0..9`(字符代码为 48..57), +- 接下来是大写字母 `A..Z`(字符代码为 65..90) +- 接下来是小写字母 `a...z`(字符代码为 97..122) -我们可以在这个序列中选择字符来创建密码(也可以添加其他特殊字符),现在先编写这个生成器。 +我们可以对这个序列进行应用,例如,我们可以从这个序列中选择字符来创建密码(也可以添加语法字符),但让我们先生成它。 -在常规函数的调用中,为了组合多个函数的结果,我们需要先依次调用它们,并分别将他们的结果存储起来,最后统一将它们合并到一起。 +在常规函数中,要合并其他多个函数的结果,我们需要调用它们,存储它们的结果,最后再将它们合并到一起。 -对于 generators 而言,我们可以使用 `yield*` 这个语法来将一个 generator 嵌入(组合)到另一个 generator 中: +对于 generator 而言,我们可以使用 `yield*` 这个特殊的语法来将一个 generator “嵌入”(组合)到另一个 generator 中: -组合式 generator 的例子: +组合的 generator 的例子: ```js run function* generateSequence(start, end) { @@ -281,9 +279,9 @@ for(let code of generatePasswordCodes()) { alert(str); // 0..9A..Za..z ``` -示例中的 `yield*` 指令负责将执行**委托**给另一个 generator。或者简单来说就是 `yield* gen` 迭代了名为 `gen` 的 generator 并显式地将 `gen` yield 的结果转发到最外部。好像这些值是由外部的 generator yield 的一样。 +`yield*` 指令将执行 **委托** 给另一个 generator。这个术语意味着 `yield* gen` 在 generator `gen` 上进行迭代,并将其 yield 的值透明地(transparently)转发到外部。就好像这些值就是由外部的 generator yield 的一样。 -执行结果和我们将嵌套的 generators 中的代码直接内联到外层generator一样: +执行结果与我们内联嵌套 generator 中的代码获得的结果相同: ```js run function* generateSequence(start, end) { @@ -314,23 +312,23 @@ for(let code of generateAlphaNum()) { alert(str); // 0..9A..Za..z ``` -**Generator 组合**是将一个 generator 流自然地插入到另一个 generator 的方式。它不需要使用额外的内存来存储中间结果。 +Generator 组合(composition)是将一个 generator 流插入到另一个 generator 流的自然的方式。它不需要使用额外的内存来存储中间结果。 -## “yield” 双向路径(two-way street) +## "yield" 是一条双向路 -目前看来,generators 和可迭代对象非常相似,仅仅是其产生 value 的语法有所不同。但实际上,generators 更加高效和灵活。 +目前看来,generator 和可迭代对象类似,都具有用来生成值的特殊语法。但实际上,generator 更加强大且灵活。 -这是因为 `yield` 是一个双向路径:它不仅向外面返回结果,而且可以将外部的值传递到 generator 内。 +这是因为 `yield` 是一条双向路(two-way street):它不仅可以向外返回结果,而且还可以将外部的值传递到 generator 内。 -调用 `generator.next(arg)`,我们就能将值 `arg` 传递到了 generator 内部。这个 `arg` 参数会变成 `yield` 语句的结果(返回值)。 +调用 `generator.next(arg)`,我们就能将参数 `arg` 传递到 generator 内部。这个 `arg` 参数会变成 `yield` 的结果。 我们来看一个例子: ```js run function* gen() { *!* - // 向外部代码传递一个问题,然后等待答案 - let result = yield "2 + 2?"; // (*) + // 向外部代码传递一个问题并等待答案 + let result = yield "2 + 2 = ?"; // (*) */!* alert(result); @@ -338,46 +336,46 @@ function* gen() { let generator = gen(); -let question = generator.next().value; // <-- yield 返回结果 +let question = generator.next().value; // <-- yield 返回的 value -generator.next(4); // --> 向 generator 传入结果 +generator.next(4); // --> 将结果传递到 generator 中 ``` ![](genYield2.svg) -1. 第一次调用 `generator.next()` 总是没有参数。它开始执行并返回第一个 `yield`(“2+2”)的结果。此时,generator 暂停执行过程(仍然在该行上)。 -2. 然后,就像上面图片中显示的那样,`yield` 的结果进入调用代码的 `question` 变量。 -3. 在 `generator.next(4)`,generator 恢复,结果为 `4`:`let result = 4`。 +1. 第一次调用 `generator.next()` 应该是不带参数的(如果带参数,那么该参数会被忽略)。它开始执行并返回第一个 `yield "2+2=?"` 的结果。此时,generator 执行暂停,而停留在 `(*)` 行上。 +2. 然后,正如上面图片中显示的那样,`yield` 的结果进入调用代码中的 `question` 变量。 +3. 在 `generator.next(4)`,generator 恢复执行,并获得了 `4` 作为结果:`let result = 4`。 -请注意,外部代码不必马上调用 `next(4)`。它可能需要一点时间来计算值是多少。这不是问题:generator 将会在调用的时候恢复。 +请注意,外部代码不必立即调用 `next(4)`。外部代码可能需要一些时间。这没问题:generator 将等待它。 -下面是有效的代码: +例如: ```js // 一段时间后恢复 generator setTimeout(() => generator.next(4), 1000); ``` -我们可以看到,与常规函数不同,generators 内部和外部调用环境可以通过 `next/yield` 来传递值,以交换结果。 +我们可以看到,与常规函数不同,generator 和调用 generator 的代码可以通过在 `next/yield` 中传递值来交换结果。 -为了使以上要点浅显易懂,我们来看另一个有更多调用的例子: +为了讲得更浅显易懂,我们来看另一个例子,其中包含了许多调用: ```js run function* gen() { - let ask1 = yield "2 + 2?"; + let ask1 = yield "2 + 2 = ?"; alert(ask1); // 4 - let ask2 = yield "3 * 3?" + let ask2 = yield "3 * 3 = ?" alert(ask2); // 9 } let generator = gen(); -alert( generator.next().value ); // "2 + 2?" +alert( generator.next().value ); // "2 + 2 = ?" -alert( generator.next(4).value ); // "3 * 3?" +alert( generator.next(4).value ); // "3 * 3 = ?" alert( generator.next(9).done ); // true ``` @@ -386,32 +384,32 @@ alert( generator.next(9).done ); // true ![](genYield2-2.svg) -1. 第一个 `.next()` 开始执行……它到达第一个 `yield`。 -2. 结果返回到外部代码中。 -3. 第二个 `.next(4)` 将 `4` 作为第一个 `yield` 结果传递回 generator 并恢复执行过程。 -4. ……此时到达第二个 `yield`,它变成了 generator 调用的结果。 -5. 第三个 `next(9)` 将 `9` 作为第二个 `yield` 的结果传入 generator 并恢复执行过程,此时到达函数最底部,从而返回 `done: true`。 +1. 第一个 `.next()` 启动了 generator 的执行……执行到达第一个 `yield`。 +2. 结果被返回到外部代码中。 +3. 第二个 `.next(4)` 将 `4` 作为第一个 `yield` 的结果传递回 generator 并恢复 generator 的执行。 +4. ……执行到达第二个 `yield`,它变成了 generator 调用的结果。 +5. 第三个 `next(9)` 将 `9` 作为第二个 `yield` 的结果传入 generator 并恢复 generator 的执行,执行现在到达了函数的最底部,所以返回 `done: true`。 -它就像“乒乓球”游戏。每个 `next(value)`(除了第一个)传递一个值到 generator,这变成了当前 `yield` 的结果,然后返回到下一个 `yield` 的结果。 +这个过程就像“乒乓球”游戏。每个 `next(value)`(除了第一个)传递一个值到 generator 中,该值变成了当前 `yield` 的结果,然后获取下一个 `yield` 的结果。 ## generator.throw -正如我们在上面例子中观察到的那样,外部代码可以将值传递到 generator,作为 `yield` 的结果。 +正如我们在上面的例子中观察到的那样,外部代码可能会将一个值传递到 generator,作为 `yield` 的结果。 -……但是它也可以在那里发起(抛出)错误。这很自然,因为错误本身也是一种结果。 +……但是它也可以在那里发起(抛出)一个 error。这很自然,因为 error 本身也是一种结果。 -要向 `yield` 传递错误,我们应该调用 `generator.throw(err)`。然后,`err` 将在对应的 `yield` 那一行被抛出。 +要向 `yield` 传递一个 error,我们应该调用 `generator.throw(err)`。在这种情况下,`err` 将被抛到对应的 `yield` 所在的那一行。 -例如,`"2 + 2?"` 的 yield 导致一个错误: +例如,`"2 + 2?"` 的 yield 导致了一个 error: ```js run function* gen() { try { - let result = yield "2 + 2?"; // (1) + let result = yield "2 + 2 = ?"; // (1) alert("The execution does not reach here, because the exception is thrown above"); } catch(e) { - alert(e); // 显示错误 + alert(e); // 显示这个 error } } @@ -424,15 +422,15 @@ generator.throw(new Error("The answer is not found in my database")); // (2) */!* ``` -在 `(2)` 行引入 generator 的错误导致 `(1)` 行 `yield` 出现异常。在上面例子中,`try..catch` 可以捕获并显示错误。 +在 `(2)` 行引入到 generator 的 error 导致了在 `(1)` 行中的 `yield` 出现了一个异常。在上面这个例子中,`try..catch` 捕获并显示了这个 error。 -如果我们没有捕获它,就像其他的异常,它将从 generator “掉出”到调用代码中。 +如果我们没有捕获它,那么就会像其他的异常一样,它将从 generator “掉出”到调用代码中。 -调用代码的当前行是 `generator.throw`,标记为 `(2)`。所以我们可以在这里捕获它,就像这样: +调用代码的当前行是 `generator.throw` 所在的那一行,标记为 `(2)`。所以我们可以在这里捕获它,就像这样: ```js run function* generate() { - let result = yield "2 + 2?"; // 这行出错 + let result = yield "2 + 2 = ?"; // 这行出现 error } let generator = generate(); @@ -443,12 +441,12 @@ let question = generator.next().value; try { generator.throw(new Error("The answer is not found in my database")); } catch(e) { - alert(e); // 显示错误 + alert(e); // 显示这个 error } */!* ``` -通常,如果我们没有在那里捕获错误,它会将错误转到外部代码(如果有的话),如果外部也没有捕获错误,则会结束脚本。 +如果我们没有在那里捕获这个 error,那么,通常,它会掉入外部调用代码(如果有),如果在外部也没有被捕获,则会杀死脚本。 ## 总结 From 6e77f1cf6fd0b7ee61d6a7eb2043fa7ebc4a3331 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 12:46:44 +0800 Subject: [PATCH 6/9] Update article.md --- 1-js/12-generators-iterators/1-generators/article.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 671b61eee2..f7f24e6039 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -343,7 +343,7 @@ generator.next(4); // --> 将结果传递到 generator 中 ![](genYield2.svg) -1. 第一次调用 `generator.next()` 应该是不带参数的(如果带参数,那么该参数会被忽略)。它开始执行并返回第一个 `yield "2+2=?"` 的结果。此时,generator 执行暂停,而停留在 `(*)` 行上。 +1. 第一次调用 `generator.next()` 应该是不带参数的(如果带参数,那么该参数会被忽略)。它开始执行并返回第一个 `yield "2 + 2 = ?"` 的结果。此时,generator 执行暂停,而停留在 `(*)` 行上。 2. 然后,正如上面图片中显示的那样,`yield` 的结果进入调用代码中的 `question` 变量。 3. 在 `generator.next(4)`,generator 恢复执行,并获得了 `4` 作为结果:`let result = 4`。 @@ -450,12 +450,12 @@ try { ## 总结 -- Generators 是被 generator 函数 `function* f(…) {…}` 创建的。 -- 在 generators(仅 generators)内部,存在 `yield` 操作。 -- 外部代码和 generator 可能会通过调用 `next/yield` 交换结果。 +- Generator 是通过 generator 函数 `function* f(…) {…}` 创建的。 +- 在 generator(仅在)内部,存在 `yield` 操作。 +- 外部代码和 generator 可能会通过 `next/yield` 调用交换结果。 -在现代 JavaScript 中,generators 很少使用。但是有时候它们会被派上用场,因为函数在执行期间与调用代码交换数据的能力是十分独特的。当然,它们非常适合制作可迭代对象。 +在现代 JavaScript 中,generator 很少被使用。但有时它们会派上用场,因为函数在执行过程中与调用代码交换数据的能力是非常独特的。而且,当然,它们非常适合创建可迭代对象。 -另外,在下一章我们将会学习 async generators,它们用于在 `for await ... of` 迭代中读取异步生成的数据流(例如,通过网络分页提取(paginated fetches over a network))。 +并且,在下一章我们将会学习 async generator,它们被用于在 `for await ... of` 循环中读取异步生成的数据流(例如,通过网络分页提取(paginated fetches over a network))。 在网络编程中,我们经常使用数据流,因此这是另一个非常重要的使用场景。 From ca9a0e223dbba00c63daf94e748fd42f07f9ebab Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 12:54:00 +0800 Subject: [PATCH 7/9] Update solution.md --- .../1-generators/01-pseudo-random-generator/solution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index 32d6aac1f5..35268645fa 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -16,7 +16,7 @@ alert(generator.next().value); // 282475249 alert(generator.next().value); // 1622650073 ``` -请注意,上面的代码也可以用普通函数来实现,就像这样: +请注意,也可以使用常规函数完成相同的操作,就像这样: ```js run function pseudoRandom(seed) { @@ -35,4 +35,4 @@ alert(generator()); // 282475249 alert(generator()); // 1622650073 ``` -这也能正常工作。但是这样我们就不能用 `for..of` 来迭代,也不能用 generator 组合了,这样的形式可能在其他地方很有用。 +这也可以工作。但是这样我们就失去了使用 `for..of` 来进行迭代以及使用 generator 组合(composition)的能力,这些可能在其他地方很有用。 From c56fe820bbed3974c916169995a01765bf351510 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 12:54:48 +0800 Subject: [PATCH 8/9] Update solution.md --- .../1-generators/01-pseudo-random-generator/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index 35268645fa..604c80fd30 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -16,7 +16,7 @@ alert(generator.next().value); // 282475249 alert(generator.next().value); // 1622650073 ``` -请注意,也可以使用常规函数完成相同的操作,就像这样: +请注意,也可以使用常规函数来完成相同的操作,就像这样: ```js run function pseudoRandom(seed) { From 6153d57d480cd2135bf79591fba964701096dab5 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Sun, 15 Mar 2020 14:58:59 +0800 Subject: [PATCH 9/9] Update task.md --- .../01-pseudo-random-generator/task.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md index 591472e71e..3e7eb7eab3 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md @@ -1,27 +1,27 @@ -# 伪随机(Pseudo-random)generator +# 伪随机 generator -在许多场合下我们都需要随机数据。 +在很多地方我们都需要随机数据。 -其中之一就是用于测试。我们可能需要随机数据:文本,数字等以便很好的测试。 +其中之一就是测试。我们可能需要随机数据:文本,数字等,以便很好地进行测试。 -在 JavaScript 中,我们可以使用 `Math.random()`。但是如果出现问题,我们希望能使用完全相同的数据再重复进行测试。 +在 JavaScript 中,我们可以使用 `Math.random()`。但是如果什么地方出现了问题,我们希望能使用完全相同的数据进行重复测试。 -为此,我们使用所谓的“种子伪随机(seeded pseudo-random)generators”。它们采用“种子”,即第一个值,然后使用公式生成下一个值。因此相同的种子 yield 相同的序列,整个数据流很容易复现。我们只需要记住种子并重复它即可。 +为此,我们可以使用所谓的“种子伪随机(seeded pseudo-random)generator”。它们将“种子(seed)”作为第一个值,然后使用公式生成下一个值。以便相同的种子(seed)可以产生(yield)相同的序列,因此整个数据流很容易复现。我们只需要记住种子并重复它即可。 -一个公式示例如下,它生成一些统一分布的值: +这样的公式的一个示例如下,它可以生成一些均匀分布的值: ``` next = previous * 16807 % 2147483647 ``` -如果我们使用 `1` 作为种子,它的值将会是: +如果我们使用 `1` 作为种子,生成的值将会是: 1. `16807` 2. `282475249` 3. `1622650073` -4. ……等等…… +4. ……等…… -那么,这里的任务是创建一个 generator 函数 `pseudoRandom(seed)`,它将 `seed` 作为参数然后以这个公式创建 generator。 +这里的任务是创建一个 generator 函数 `pseudoRandom(seed)`,它将 `seed` 作为参数并使用此公式创建 generator。 使用范例: