<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 38. 異步函數 > 原文: [http://exploringjs.com/impatient-js/ch_async-functions.html](http://exploringjs.com/impatient-js/ch_async-functions.html) > > 貢獻者:[iChrisJ](https://github.com/iChrisJ) 粗略地說,_異步函數_ 為使用 Promise 的代碼提供了更好的語法。 ### 38.1. 異步函數:基礎知識 考慮以下異步函數: ```JavaScript async function fetchJsonAsync(url) { try { const request = await fetch(url); // async const text = await request.text(); // async return JSON.parse(text); // sync } catch (error) { assert.fail(error); } } ``` 上面看起來相似于同步的代碼是相等于下面基于 Promise 的代碼: ```JavaScript function fetchJsonViaPromises(url) { return fetch(url) // async .then(request => request.text()) // async .then(text => JSON.parse(text)) // sync .catch(error => { assert.fail(error); }); } ``` 關于異步函數`fetchJsonAsync()`的一些觀察: * 異步函數標有關鍵字`async`。 * 在異步函數體內,您可以編寫基于 Promise 的代碼,就好像它是同步的一樣。只要其值為 Promise,您只需要添加`await`運算符。該運算符暫停異步函數并在 Promise 結算后恢復: * 如果那個 Promise 被履行,`await`將返回其履行值。 * 如果那個 Promise 被拒絕,`await`會拋出其拒絕值。 * 異步函數的結果始終是一個 Promise: * 返回的任何值(顯式或隱式)用于實現 Promise。 * 拋出的任何異常都用于拒絕 Promise。 `fetchJsonAsync()`和`fetchJsonViaPromises()`都以完全相同的方式調用,如下所示: ```JavaScript fetchJsonAsync('http://example.com/person.json') .then(obj => { assert.deepEqual(obj, { first: 'Jane', last: 'Doe', }); }); ``` #### 38.1.1. 異步構造 JavaScript 具有以下異步版本的同步可調用實體。他們的角色總是真實的函數或方法。 ```JavaScript // Async function declaration async function func1() {} // Async function expression const func2 = async function () {}; // Async arrow function const func3 = async () => {}; // Async method definition (in classes, too) const obj = { async m() {} }; ``` #### 38.1.2. 異步函數總是返回 Promise 每個異步函數總是返回一個 Promise。 在異步函數中,您通過`return`(A 行)履行 Promise 結果: ```JavaScript async function asyncFunc() { return 123; // (A) } asyncFunc() .then(result => { assert.equal(result, 123); }); ``` 像往常一樣,如果您沒有顯式地返回任何內容,則會為您返回`undefined`: ```JavaScript async function asyncFunc() { } asyncFunc() .then(result => { assert.equal(result, undefined); }); ``` 您通過`throw`(A 行)返回 Promise 被拒絕的結果 Promise: ```JavaScript let thrownError; async function asyncFunc() { thrownError = new Error('Problem!'); throw thrownError; // (A) } asyncFunc() .catch(err => { assert.equal(err, thrownError); }); ``` #### 38.1.3. 返回的 Promise 沒有包裝 如果從異步函數返回一個 Promise `p`,則`p`成為函數的結果(或者更確切地說,結果“鎖定”在`p`上并且與它的行為完全相同)。也就是說,Promise 并不會包含在另一個 Promise 中。 ```JavaScript async function asyncFunc() { return Promise.resolve('abc'); } asyncFunc() .then(result => assert.equal(result, 'abc')); ``` 回想一下,在以下情況下,任何 Promise `q`都會被類似地處理: * `new Promise((resolve, reject) => { ··· })`內的`resolve(q)` * `.then(result => { ··· })`內的`return q` * `.catch(err => { ··· })`內的`return q` #### 38.1.4. `await`:與 Promise 一起工作 `await`運算符只能在異步函數中使用。它的操作對象通常是一個 Promise,并引導執行以下步驟: * 當前的異步功能被暫停(類似于使用`yield`時[同步生成器](ch_sync-generators.html)是如何暫停一樣)。 * 繼續處理任務隊列。 * 一旦 Promise 得到解決,異步函數就會恢復: * 如果 Promise 被履行,`await`將返回履行值。 * 如果 Promise 被拒絕,`await`會拋出拒絕值。 以下兩節提供了更多詳細信息。 #### 38.1.5. `await` 與被履行的 Promise 如果其操作對象最終成為被履行的 Promise,`await`將返回其履行值: ```JavaScript assert.equal(await Promise.resolve('yes!'), 'yes!'); ``` 也允許非 Promise 值,并簡單地傳遞(同步,沒有異步函數的暫停): ```JavaScript assert.equal(await 'yes!', 'yes!'); ``` #### 38.1.6. `await`與被拒絕的 Promise 如果其操作對象是被拒絕的 Promise,則`await`會拋出拒絕值: ```JavaScript try { await Promise.reject(new Error()); assert.fail(); // we never get here } catch (e) { assert.equal(e instanceof Error, true); } ``` `Error`的實例(包括其子類的實例)將被特別處理并拋出: ```JavaScript try { await new Error(); assert.fail(); // we never get here } catch (e) { assert.equal(e instanceof Error, true); } ``` ![](https://img.kancloud.cn/3e/d5/3ed5755d562179ae6c199264f5e21157.svg) **練習:Fetch API** 通過異步函數 `exercises/async-functions/fetch_json2_test.js` ### 38.2. 術語 讓我們澄清幾個術語: * _異步函數_,_異步方法_:使用關鍵字`async`定義。異步函數也稱為 _async/await_ ,基于作為其語法基礎的兩個關鍵字。 * _直接使用 Promise_ :意味著代碼在沒有`await`的情況下處理 Promise。 * _基于 Promise 的_:通過 Promises 提供結果和錯誤的函數或方法。也就是說,異步函數和返回 Promises 的函數都是合格的。 * _異步_:異步地傳遞結果和錯誤的函數或方法。這里,任何使用異步模式(回調,事件,Promise 等)的操作都是合格的。唉,事情有點令人困惑,因為“異步函數(async function)”中的“異步(async)”是“異步(asynchronous)”的縮寫。 ### 38.3. `await`很淺(你不能在回調中使用它) 如果你在異步函數中并希望通過`await`暫停它,則必須在該函數中執行此操作,不能在嵌套函數中使用它,例如回調。也就是說,暫停是 _淺_。 例如,以下代碼無法執行: ```JavaScript async function downloadContent(urls) { return urls.map((url) => { return await httpGet(url); // SyntaxError! }); } ``` 原因是普通箭頭函數不允許`await`進入其函數體內。 好的,讓我們嘗試異步箭頭函數,然后: ```JavaScript async function downloadContent(urls) { return urls.map(async (url) => { return await httpGet(url); }); } ``` 唉,這也行不通:現在`.map()`(還有 `downloadContent()`)返回一個帶 Promise 的數組,而不是帶有(未包裝)值的數組。 一種可能的解決方案是使用`Promise.all()`解除所有 Promise 地包裝: ```JavaScript async function downloadContent(urls) { const promiseArray = urls.map(async (url) => { return await httpGet(url); // (A) }); return await Promise.all(promiseArray); } ``` 這段代碼可以改進嗎?是的,它可以,因為在 A 行,我們通過`await`展開 Promise,只是通過`return`立即重新包裝它。我們可以省略`await`,然后甚至不需要異步箭頭函數: ```JavaScript async function downloadContent(urls) { const promiseArray = urls.map( url => httpGet(url)); return await Promise.all(promiseArray); // (B) } ``` 出于同樣的原因,我們也可以省略 B 行中的`await`。 ![](https://img.kancloud.cn/3e/d5/3ed5755d562179ae6c199264f5e21157.svg) **練習:異步映射和過濾** `exercises/async-functions/map_async_test.js` ### 38.4. (高級) 所有剩余部分都是高級的。 ### 38.5. 立即調用異步箭頭函數 如果在異步函數外需要`await`(例如,在模塊的頂層),則可以立即調用異步箭頭函數: ```JavaScript (async () => { // start const promise = Promise.resolve('abc'); const value = await promise; assert.equal(value, 'abc'); })(); // end ``` 立即調用異步箭頭函數的結果是一個 Promise: ```JavaScript const promise = (async () => 123)(); promise.then(x => assert.equal(x, 123)); ``` ### 38.6. 并發和`await` #### 38.6.1. `await`:順序運行異步函數 如果你用`await`為多個異步函數的調用添加前綴,那么這些函數將按順序執行: ```JavaScript const otherAsyncFunc1 = () => Promise.resolve('one'); const otherAsyncFunc2 = () => Promise.resolve('two'); async function asyncFunc() { const result1 = await otherAsyncFunc1(); assert.equal(result1, 'one'); const result2 = await otherAsyncFunc2(); assert.equal(result2, 'two'); } ``` 也就是說,`otherAsyncFunc2()`僅在`otherAsyncFunc1()`完全結束后才開始。 #### 38.6.2. `await`:并發地運行異步函數 如果我們想同時運行多個函數,我們需要求助于工具方法`Promise.all()`: ```JavaScript async function asyncFunc() { const [result1, result2] = await Promise.all([ otherAsyncFunc1(), otherAsyncFunc2(), ]); assert.equal(result1, 'one'); assert.equal(result2, 'two'); } ``` 這里,兩個異步函數同時啟動。一旦兩者都結算了,`await`給我們一個履行值數組或者 —— 如果至少有一個 Promise 被拒絕 —— 一個異常。 回想一下前一章,重要的是當你開始一個基于 Promise 的計算 - 而不是你如何處理它的結果。因此,以下代碼與前一個代碼一樣“并發”: ```JavaScript async function asyncFunc() { const promise1 = otherAsyncFunc1(); const promise2 = otherAsyncFunc2(); const result1 = await promise1; const result2 = await promise2; assert.equal(result1, 'one'); assert.equal(result2, 'two'); } ``` ### 38.7. 使用異步功能的小技巧 #### 38.7.1. 異步函數同步啟動,異步結算 異步函數執行如下: * 當異步函數啟動時會創建其結果的 Promise `p`。 * 然后函數體被執行。執行可以通過兩種方式返回: * 執行可以永久返回,同時結算`p`: * `return`一個已滿足的`p`。 * `throw`一個被拒絕的`p`。 * 執行也可以暫時離開,當通過`await`等待另一個 Promise `q`的結算時。異步函數被暫停,執行離開它。一旦`q`被結算,它就會恢復。 * Promise `p`在執行首次(永久或暫時)離開函數體后返回。 請注意,結果`p`的結算通知是異步發生的,Promise 的情況也是如此。 下面的代碼演示了異步函數是同步啟動的(行 A),然后當前任務完成(行 C),然后結果 Promise 得到解決 —— 異步(行 B)。 ```JavaScript async function asyncFunc() { console.log('asyncFunc() starts'); // (A) return 'abc'; } asyncFunc(). then(x => { // (B) console.log(`Resolved: ${x}`); }); console.log('Task ends'); // (C) // Output: // 'asyncFunc() starts' // 'Task ends' // 'Resolved: abc' ``` #### 38.7.2. 如果你是“觸發后遺忘”那你不需要`await` 當使用一個基于 Promise 的函數時`await`不是必須的,如果要暫停并等到返回的 Promise 結算,則才需要它。如果你想要做的只是啟動異步操作,那么你不需要它: ```JavaScript async function asyncFunc() { const writer = openFile('someFile.txt'); writer.write('hello'); // don't wait writer.write('world'); // don't wait await writer.close(); // wait for file to close } ``` 在此代碼中,我們不等待`.write()`,因為我們不關心它何時完成。但是,我們確實要等到`.close()`完成。 #### 38.7.3. 它對`await`有意義并忽略結果 即使您忽略其結果,使用`await`偶爾也會有意義。例如: ```JavaScript await longRunningAsyncOperation(); console.log('Done!'); ``` 在這里,我們使用`await`加入長時間運行的異步操作。這確保了寫日志確實發生操作完成 _后_。
                  <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>

                              哎呀哎呀视频在线观看