JavaScript yield

引入:迭代器和生成器的概念

在深入探讨 yield 关键字之前,我们有必要先了解一些基本概念。迭代器(Iterator)是一种设计模式,用于遍历集合中的元素,而无需暴露其底层表示形式。ES6 引入了内置的迭代器接口,使开发者可以更容易地实现这一模式。

生成器(Generator)是另一种特殊的函数类型,允许在执行过程中暂停并恢复。这使得它们非常适合处理需要逐步计算或异步操作的数据流。生成器通过 function* 语法定义,并使用 yield 关键字来控制函数的暂停和恢复。

yield 的基本用法

定义生成器函数

生成器函数通过在 function 关键字后面添加一个星号(*)来定义。这与普通函数不同,生成器函数可以返回多个值,这些值通过 yield 关键字传递。

使用生成器

生成器对象可以通过调用生成器函数来创建。一旦生成器被创建,你可以通过调用 .next() 方法来获取下一个生成的值。当遇到 yield 关键字时,函数将暂停,并返回一个包含当前 valuedone 属性的对象。

yield 与返回值

单次返回

生成器函数也可以像普通函数一样返回一个值。这个返回值会被作为生成器对象的 return 方法的结果。当调用 .return() 方法时,生成器会立即停止执行,并返回指定的值。

-- -------------------- ---- -------
--------- ------------- -
    ----- --------
    ------ ------ -------
-

----- --------- - --------------

------------------------------ -- - ------ -------- ----- ----- -
------------------------------ -- - ------ ------ ------- ----- ---- -
-------------------------------------- ------------ -- - ------ --------- ---------- ----- ---- -

多次返回

尽管生成器函数只允许一次返回值,但你可以在生成器内部多次调用 .return() 方法。后续的 .return() 调用不会改变先前返回值的效果。

-- -------------------- ---- -------
--------- ------------- -
    ----- ------
    ------ ------
    ----- -------- -- ---- ---- --- -- -------
-

----- --------- - --------------

------------------------------ -- - ------ ------ ----- ----- -
------------------------------ -- - ------ ------ ----- ---- -
------------------------------ -- - ------ ---------- ----- ---- -

yield 与错误处理

抛出异常

生成器函数可以通过调用 throw 方法来抛出异常。这会使生成器暂停执行,并在生成器内部引发异常。如果未捕获,则生成器将继续执行直到完成。

-- -------------------- ---- -------
--------- ------------- -
    --- -
        ----- --------
        ----- --- --------- ----- -----------
        ----- ------
    - ----- ------- -
        ----------------------------- -- --- ----- ---------
        ----- ------------
    -
-

----- --------- - --------------

------------------------------ -- - ------ -------- ----- ----- -
------------------------------- ------------ ----------- -- - ------ ------------ ----- ----- -

捕获异常

生成器函数可以通过在生成器内部使用 try...catch 结构来捕获并处理异常。这有助于在生成器暂停和恢复执行时进行错误处理。

-- -------------------- ---- -------
--------- ------------- -
    --- -
        ----- --------
        ----- ---------
        ----- --- ----------------- --------
    - ----- ------- -
        ----------------------------- -- ----------- ------
        ----- ------------
    -
-

----- --------- - --------------

------------------------------ -- - ------ -------- ----- ----- -
------------------------------ -- - ------ --------- ----- ----- -
------------------------------- ------------ ----------- -- - ------ ------------ ----- ----- -

yield 与 for-of 循环

遍历生成器

生成器对象可以与 for-of 循环结合使用,以便更方便地遍历生成器产生的序列。for-of 循环会自动调用生成器的 .next() 方法,直到生成器完成。

-- -------------------- ---- -------
--------- ------------- -
    ----- ----- -----
    ----- ----- -----
    ----- ----- -------
-

--- ---- ---- -- -------------- -
    ------------------
-
-- ---
-- ---- ---
-- ---- ---
-- ---- -----

使用生成器作为数据源

生成器不仅可以用作简单的数据生成器,还可以用于处理复杂的数据流。例如,可以使用生成器来读取文件、处理网络请求等。

-- -------------------- ---- -------
----- --------- ------------------- -
    ----- ---------- - ----------------------------- --------
    --- ------- - ---

    --- ----- ------ ----- -- ----------- -
        ------- -- ------
        ----- ----- - --------------------
        -- ------------- - -- -
            ----- --------------
        -
        ------- - ------------
    -

    -- --------- -
        ----- --------
    -
-

------ -- -- -
    --- ----- ------ ---- -- ------------------------- -
        ------------------
    -
-----

yield 与并发编程

协程与并发

生成器可以用来实现协程(Coroutine),这是一种轻量级的并发编程模型。通过使用生成器和 yield 关键字,可以实现非阻塞的并发操作。

-- -------------------- ---- -------
--------- ----------- -
    ----- ------- - ----- -----------------
    ----- ------- - ----- ------------------------
    ----- ------- - ----- ------------------------
    ------ --------
-

-------- ---------------- -
    ------ --- --------------- -- ------------- -- --------------- ---- -------
-

-------- --------------------- -
    ------ --- --------------- -- ------------- -- --------------- - ---- ----------- ------
-

-------- --------------------- -
    ------ --- --------------- -- ------------- -- --------------- - ---- ----------- ------
-

----- --- - ------------

-------- ------ -
    ----- - ------ ---- - - -----------
    -- ------- -
        ----------------- -- -
            -----------------
            ---------------- ---
        ---
    -
-

---------------- ---

yield 与惰性求值

惰性求值

生成器的一个强大特性是它们支持惰性求值(Lazy Evaluation)。这意味着只有在需要时才会计算生成器中的值,从而提高性能并减少不必要的计算。

-- -------------------- ---- -------
--------- ------------------ -
    --- ---- - - -- - - --- ---- -
        ----- - - --
    -
-

----- -------- - -------------------

----------------------------------- -- -
----------------------------------- -- -
----------------------------------- -- -
-- ---------------

yield 与其他语言的比较

ECMAScript 与 Python

虽然 yield 关键字在 JavaScript 中引入,但它与 Python 中的 yield 类似,都用于生成器函数。然而,两者在语法和实现上有一些细微差别。

  • Python:

  • JavaScript:

ECMAScript 与 C#

C# 中的迭代器

C# 也支持类似的功能,通过 yield return 来实现。虽然语法有所不同,但基本概念是相同的。

-- -------------------- ---- -------
------ ------------------- ------------- -
    ----- ------ --------
    ----- ------ --------
-

--- --------- - --------------
------- ---- ---- -- ---------- -
    ------------------------
-
-- ---
-- -----
-- -----

yield 与异步编程

异步生成器

随着异步编程的流行,JavaScript 引入了异步生成器(Async Generators),它结合了 asyncyield 的功能,允许生成器在等待异步操作的同时继续产生值。

-- -------------------- ---- -------
----- --------- ---------------- -
    ----- --------
    ----- ---------
    ----- --- --------------- -- ------------------- -------
    ----- --------
-

------ -- -- -
    ----- --- - -----------------
    ----------------- ------------ -- - ------ -------- ----- ----- -
    ----------------- ------------ -- - ------ --------- ----- ----- -
    ----- --- --------------- -- ------------------- -------
    ----------------- ------------ -- - ------ -------- ----- ----- -
-----

并发控制

生成器和异步生成器还支持并发控制,例如使用 Promise.allPromise.race 来管理多个异步操作。

-- -------------------- ---- -------
----- --------- ---------------------- -
    ----- -------- - -
        -----------------
        -----------------
        ----------------
    --

    ----- ------- - ----- -------------------------------- -- --------------- -- -----
    --- ------ ------ -- -------- -
        ----- -------
    -
-

----- -------- ---------------- -
    ------ --- --------------- -- ------------- -- --------------- ---- -------
-

----- -------- ---------------- -
    ------ --- --------------- -- ------------- -- --------------- ---- ------
-

----- -------- ---------------- -
    ------ --- --------------- -- ------------- -- --------------- ---- ------
-

------ -- -- -
    ----- --- - -----------------------
    ----------------- ------------
    ----------------- ------------
    ----------------- ------------
-----

总结

通过本章的学习,你应该对 yield 关键字有了深入的理解。从基本用法到高级技巧,生成器为处理复杂数据流提供了强大的工具。无论是处理文件、网络请求,还是实现并发控制,生成器都是不可多得的好帮手。希望你能够在未来项目中灵活运用这些知识!

上一篇: JavaScript await
下一篇: JavaScript in
纠错
反馈