成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JavaScript 異步編程指南 — 解決方案 Async/Await

開發 前端
ES7 之后引入了 Async/Await 解決異步編程,這種方式在 JavaScript 異步編程中目前也被稱為 “終極解決方案”。

[[407624]]

本文轉載自微信公眾號「五月君」,作者五月君。轉載本文請聯系五月君公眾號。

ES7 之后引入了 Async/Await 解決異步編程,這種方式在 JavaScript 異步編程中目前也被稱為 “終極解決方案”。

基本使用

函數聲明時在 function 關鍵詞之前使用 async 關鍵字,內部使用 await 替換了 Generator 中的 yield,語義上比起 Generator 中的 * 號也更明確。

在執行時相比 Generator 而言,Async/Await 內置執行器,不需要 co 這樣的外部模塊,程序語言本身實現是最好的,使用上也更簡單。

聲明 async 函數

以下是基于 Generator 一講中的一個例子做了改造,在第二個 await 后面,使用 Promise 封裝了下,它本身是支持跟一個 Promise 對象的,這個時候它會等待當 Promise 狀態變為 Fulfilled 才會執行下一步,當 Promise 未能正常執行 resolve/reject 時那就意味著,下面的也將得不到執行。

await 后面還可跟上基本類型:數值、字符串、布爾值,但這時也會立即轉成 Fulfilled 狀態的 Promise。

  1. async function test() { 
  2.   const res1 = await 'A'
  3.   const res2 = await Promise.resolve(res1 + 'B'); 
  4.   const res3 = await res2 + 'C'
  5.   return res3; 
  6.  
  7. (async () => { 
  8.   const res = await test(); // ABC 
  9. })(); 

錯誤管理

如果 await 后面的 Promise 返回一個錯誤,需要 try/catch 做錯誤捕獲,若有多個 await 操作也可都放在一起。這種情況,假如第一個 await 后面的 Promise 報錯,第二個 await 是不會執行的。

這和普通函數操作基本上是一樣的,不同的是對于異步函數我們需要加上 await 關鍵字。

  1. (async () => { 
  2.   try { 
  3.    await fetch1(url); 
  4.    await fetch2(url); 
  5.   } catch (err) { 
  6.    // TODO 
  7.   } 
  8. })(); 

也要注意 await 必須寫在 async 函數里,否則會報錯 SyntaxError: await is only valid in async functions and the top level bodies of modules。

  1. // 錯誤的操作 
  2. (() => { 
  3.   await 'A'
  4. })(); 

這樣寫也是不行的,在 “協程” 一講中也提過類似的示例,只不過當時是基于 yield 表達式,async/await 實際上是 Generator 函數的一種語法糖,內部機制是一樣的,forEach 里面的匿名函數是一個普通的函數,運行時會被看作是一個子函數,棧式協程是從子函數產生的,而 ES6 中實現的協程屬于無堆棧式協程,只能從生成器內部生成。以下代碼在運行時會直接失敗。

  1. (async () => { 
  2.   ['B''C'].forEach(item => { 
  3.     const res = await item; 
  4.     console.log(res); 
  5.   }) 
  6. })(); 

想通過 await 表達式正常運行,就要避免使用回調函數,可以使用遍歷器 for...of。

  1. (async () => { 
  2.   for (const item of ['B''C']) { 
  3.     const res = await item; // B C 
  4.   } 
  5. })(); 

并發執行

當我們擁有多個異步請求,且不必順序執行時,可以在 await 表達式后使用 Promise.all(),這是一個很好的實踐。

  1. (async () => { 
  2.   await Promise.all([ 
  3.    fetch(url1), 
  4.     fetch(ur2) 
  5.   ]) 
  6. })(); 

通過這個示例可以看出,async/await 也還是基于 Promise 的。

異步迭代

上面講解的使用 Async/Await 都是基于單次運行的異步函數,在 Node.js 中我們還有一類需求它來自于連續的事件觸發,例如,基于流式 API 讀取數據,常見的是注冊 on('data', callback) 事件和回調函數,但是這樣我們不能利用常規的 Async/Await 表達式來處理這類場景。

異步迭代器

異步迭代器與同步迭代器不同的是,一個可迭代的異步迭代器對象具有 [Symbol.asyncIterator] 屬性,并且返回的是一個 Promise.resolve({ value, done }) 結果。

實現異步迭代器比較方便的方式是使用聲明為 async 的生成器函數,可以使我們像常規函數中一樣去使用 await,以下展示了 Node.js 可讀流對象是如何實現的異步可迭代,只列出了核心代碼,異步迭代器筆者也有一篇詳細的文章介紹,很精彩,感興趣的可以看看 探索異步迭代器在 Node.js 中的使用。

  1. // for await...of 循環會調用 
  2. Readable.prototype[SymbolAsyncIterator] = function() { 
  3.   ... 
  4.   const iter = createAsyncIterator(stream); 
  5.   return iter; 
  6. }; 
  7.  
  8. // 聲明一個創建異步迭代器對象的生成器函數 
  9. async function* createAsyncIterator(stream) { 
  10.   ... 
  11.   try { 
  12.     while (true) { 
  13.       // stream.read() 從內部緩沖拉取并返回數據。如果沒有可讀的數據,則返回 null 
  14.       // readable 的 destroy() 方法被調用后 readable.destroyed 為 true,readable 即為下面的 stream 對象 
  15.       const chunk = stream.destroyed ? null : stream.read(); 
  16.       if (chunk !== null) { 
  17.         yield chunk; // 這里是關鍵,根據迭代器協議定義,迭代器對象要返回一個 next() 方法,使用 yield 返回了每一次的值 
  18.       } 
  19.       ... 
  20.     } 
  21.   } catch (err) { 
  22.   } 

for...await...of 遍歷器

Node.js Stream 模塊的可讀流對象在 v10.0.0 版本試驗性的支持了 [Symbol.asyncIterator] 屬性,可以使用 for await...of 語句遍歷可讀流對象,在 v11.14.0 版本以上已 LTS 支持,這使得我們從流中讀取連續的數據塊變的很方便。

  1. const fs = require('fs'); 
  2. const readable = fs.createReadStream('./hello.txt', { encoding: 'utf-8' }); 
  3.  
  4. async function readText(readable) { 
  5.   let data = ''
  6.   for await (const chunk of readable) { 
  7.     data += chunk; 
  8.   } 
  9.   return data; 
  10.  
  11. (async () => { 
  12.   try { 
  13.     const res = await readText(readable); 
  14.     console.log(res); // Hello Node.js 
  15.   } catch (err) { 
  16.     console.log(err.message); 
  17.   } 
  18. })(); 

使用 **for await...of** 語句遍歷 readable,如果循環中因為 break 或 throw 一個錯誤而終止,則這個 Stream 也將被銷毀。

頂級 Await

根據 async 函數語法規則,await 只能出現在 async 異步函數內。對于異步資源,之前我們必須在 async 函數內才可使用 await,這對一些在文件頂部需要實例化的資源可能會不好操作。

在 Node.js v14.x LTS 發布后,已支持頂級 Await 我們可以方便的在文件頂部對這些異步資源做一些初始化操作。

我們可以像下面這樣來寫,但這種模式也只有在 ES Modules 中才可用。

  1. import fetch from 'node-fetch'
  2. const res = await fetch(url) 

總結

JavaScript 編程中大部分操作都是異步編程,Async/Await 可以已同步的方式來書寫我們的代碼,但是實際執行其還是異步的,這種被方式目前也稱為異步編程的終極解決方案。

 

責任編輯:武曉燕 來源: 五月君
相關推薦

2017-08-02 14:17:08

前端asyncawait

2014-07-15 10:08:42

異步編程In .NET

2016-11-22 11:08:34

asyncjavascript

2023-07-28 07:31:52

JavaScriptasyncawait

2021-07-20 10:26:12

JavaScriptasyncawait

2021-11-01 22:36:04

JavaScript

2024-06-25 08:33:48

2018-05-13 21:57:04

JavaScript異步編程方案

2024-12-23 08:00:45

2021-06-06 19:51:07

JavaScript異步編程

2013-05-16 10:33:11

C#C# 5.0Async

2023-11-03 14:32:38

2024-10-14 08:29:14

異步編程任務

2024-10-07 08:28:03

WPFUI應用程序

2024-11-13 01:00:18

asyncawait?編程

2020-10-15 13:29:57

javascript

2024-09-02 14:12:56

2013-03-14 11:18:30

Microsoft A解決方案

2025-04-08 00:22:00

C#異步編程

2018-12-19 18:40:28

JavaScriptes6 前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 新av在线| av中文字幕在线观看 | 日本黄色大片免费 | 亚洲欧美国产毛片在线 | 日韩视频免费看 | 美女黄视频网站 | 国产乱一区二区三区视频 | 日韩三级一区 | 在线观看精品 | 视频一区二区三区在线观看 | 国产99视频精品免费播放照片 | 亚洲精品99 | 亚洲国产精品久久久 | 日韩在线欧美 | 99热热 | 黄色av网站免费看 | 好姑娘高清在线观看电影 | 一级毛片视频 | 久久国产精品网站 | 久久久久亚洲 | 中文字幕第5页 | 日韩成人免费视频 | 天天宗合网 | 日韩一区二区三区视频 | 91九色麻豆 | 久久99精品久久久久久国产越南 | 国产精品成人国产乱一区 | 成人aaa视频 | 久久福利网站 | 亚洲一区二区三区视频 | 免费人成激情视频在线观看冫 | 日韩中文字幕一区二区 | 久久精品色欧美aⅴ一区二区 | 免费在线成人 | 亚洲三级av| 尹人av | 自拍视频在线观看 | 一区二区在线 | 妹子干综合 | 免费xxxx大片国产在线 | 日韩不卡在线 |