<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 22. 生成器 Generators 示例代碼:[generator-examples](https://github.com/rauschma/generator-examples) ## 22.1 概述 ### 22.1.1 什么是生成器? 你可以將生成器視為可以暫停和恢復的進程(一段代碼): ```js function* genFunc() { // (A) console.log('First'); yield; console.log('Second'); } ``` 注意生成器的語法:`function*` 標志該函數為生成器函數(相對也有生成器方法); `yield` 可以暫停生成器,此外通過它,生成器還能接受輸入和發送輸出。 調用一個生成器函數時,就會得到一個生成器對象`genObj`,通過該對象來實現進程控制(control the process:): ```js const genObj = genFunc(); ``` 整個進程一開始處于暫停(位于A行),`genObj.next()`將恢復執行,然后`yield`將暫停執行: ```js genObj.next(); // Output: First genObj.next(); // output: Secon ``` ### 22.1.2 生成器的種類 有四種生成器: 1. 生成器函數聲明: ```js function* genFunc() {...} const genObj = genFunc(); ``` 2. 生成器函數表達式: ```js const genFunc = function* () {...}; const genObj = genFunc(); ``` 3. 對象字面量中生成器方法的定義: ```js const obj = { * generatorMethod(){ ... } }; const genObj = obj.generatorMethod(); ``` 4. 類中的生成器方法的定義: ```js class MyClass { * generatorMethod(){ ... } } const myInst = new MyClass(); const genObj = myInst.generatorMethod(); ``` ### 22.1.3 案例:實現迭代 生成器返回的對象是可迭代的;每個`yield` 按需產生迭代值。因此我們可以使用生成器來實現可迭代值,可以被各種ES6語言機制使用:例如`for-of`循環、展開運算符(`…`)等。 下面的函數返回一個對象的屬性迭代值,每個屬性對應的`[key,value]`: ```js function* objectEntries(obj){ const propKeys = Reflect.ownKeys(obj); for(const propKey of propKeys){ // `yield` returns a value and then pauses // the generator. Later, execution continues // where it was previously paused. yield [propKey, obj[propKey]]; } } ``` 然后使用 `objectEntries()`: ```js const jane = { first: 'Jane', last: 'Doe' }; for (const [key,value] of objectEntries(jane)) { console.log(`${key}: ${value}`); } // Output: // first: Jane // last: Doe ``` 具體`objectEntries()` 如何工作的,在專門部分中有解釋。 實現同樣的功能,不使用生成器的話,需要花費更多的工作。 ### 22.1.4 案例:更簡單的異步代碼 使用生成器可以很大程度上簡化了`Promises`的工作。 下面看一下基于`Promise`的`fetchJson()`怎么通過生成器來進行改善: ```js function fetchJson(url){ return fetch(url) .then(request => request.text()) .then(text => { return JSON.parse(text); }) .catch(error => { console.log(`ERROR:${error.stack}`); }); } ``` 通過[co](https://github.com/tj/co)庫和生成器,使得異步代碼看起來是同步的: ```js const fetchJson = co.wrap(function* (url) { try { let request = yield fetch(url); let text = yield request.text(); return JSON.parse(text); } catch (error) { console.log(`ERROR: ${error.stack}`); } ``` ECMAScript 2017 發布的 `async`,內部是基于生成器的。可以像下面這樣使用: ```js async function fetchJson(url){ try { let request = await fetch(url); let text = await request.text(); return JSON.parse(text); } catch (error) { console.log(`ERROR: ${error.stack}`); } } ``` 使用時,上面的所有版本代碼都可以如下調用: ```js fetchJson('http://example.com/some_file.json') .then(obj => console.log(obj)); ``` ### 22.1.5 案例:接收異步數據: 生成器可以通過`yield` 從 `next()` 接收輸入。這意味著只要新數據異步到達生成器就可以喚醒生成器,感覺就像它同步接收數據一樣。 ## 什么是生成器 生成器是可以暫停和恢復的函數(可以考慮協同多任務處理(cooperative multitasking)或協同程序(coroutines)),它支持各種應用程序。 首先,看如下名為`genFunc`的生成器函數: ```js function* genFunc() { // (A) console.log('First'); yield; // (B) console.log('Second'); // (C) } ``` 可以看出,它與普通函數的兩點區別: *. 使用了`function*` 進行聲明。 *. 可以通過 `yield`,暫停自身的執行(行B)。 調用 `genFunc` 不會執行代碼主體,會得到一個 生成器對象,用來對執行主體的控制。 ```js const genObj = genFunc(); ``` `genFunc()` 一開始會在代碼主體執行之前暫停(行A)。調用 `genObj.next()`會執行到下一個`yield`位置: ```js > genObj.next() First { value: undefined, done: false } ``` 可以看到`genObj.next()`返回了一個對象。接著看下面... `genFunc` 現在在行B處暫停。如果在調用`next()`,執行進程恢復,行C被執行: ```js > genObj.next() Second { value: undefined, done: true } ``` 之后,該函數執行完畢,離開函數體;接下來再執行`genObj.next()` 是沒有任何效果的。 ### 22.2.1 生成器的用處 在三個方面扮演重要作用: 1. 迭代器(數據生產者): 每個`yield` 都可以通過next()返回一個值,這意味著生成器可以通過循環和遞歸生成值序列。由于生成器對象實現了Iterable接口(在[迭代章節](http://exploringjs.com/es6/ch_iteration.html#ch_iteration)中有解釋),這些序列可以由任何支持iterables的ECMAScript 6構造處理。兩個例子是:`for-of`循環和擴展運算符(`...`)。 2. 觀察者(數據消費者): `yield` 也可以從 `next()`(通過參數)接收值。這意味著生成器會成為數據使用者,在通過`next()`向它們推送新值之前會暫停。 4. 協同程序(數據生產者和消費者): 考慮到生成器是可暫停的,可以同時是數據生產者和數據消費者,將它們轉換為協同程序(協作的多任務任務) (coroutines (cooperatively multitasked tasks))不需要做太多工作。 接下來會對這些角色進行更深入的解釋。 ## 22.3 作為迭代器的生成器(數據生成) 可以查看[上一章 迭代器](http://exploringjs.com/es6/ch_iteration.html#ch_iteration)的相關知識。 ## 22.5 作為協程的生成器(協同多任務處理)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看