ES2017非同步函式現已正式可用
ES2017標準已於2017年6月份正式定稿了,並廣泛支援最新的特性:非同步函式。如果你曾經被非同步 JavaScript 的邏輯困擾,這麼新函式正是為你設計的。
非同步函式或多或少會讓你編寫一些順序的 JavaScript 程式碼,但是卻不需要在 callbacks、generators 或 promise 中包含你的邏輯。
如下程式碼:
function logger() { let data = fetch('') console.log(data) } logger()
這段程式碼並未實現你的預期。如果你是在JS中編寫的,那麼你可能會知道為什麼。
下面這段程式碼,卻實現了你的預期。
async function logger() { let data = await fetch('http:sampleapi.com/posts') console.log(data) } logger()
這段程式碼起作用了,從直觀上看,僅僅只是多了 async 和 await 兩個詞。
ES6 標準之前的 JavaScript 非同步函式
在深入學習 async 和 await 之前,我們需要先理解 Promise。為了領會 Promise,我們需要回到普通回撥函式中進一步學習。
Promise 是在 ES6 中引入的,並促使在編寫 JavaScript 的非同步程式碼方面,實現了巨大的提升。從此編寫回撥函式不再那麼痛苦。
回撥是一個函式,可以將結果傳遞給函式並在該函式內進行呼叫,以便作為事件的響應。同時,這也是JS的基礎。
function readFile('file.txt', (data) => { // This is inside the callback function console.log(data) }
這個函式只是簡單的向檔案中記錄資料,在檔案完成之前進行讀取是不可能的。這個過程似乎很簡單,但是如果想要按順序讀取並記錄五個不同的檔案,需要怎麼實現呢?
沒有 Promise 的時候,為了按順序執行任務,就需要透過巢狀回撥來實現,就像下面的程式碼:
// This is officially callback hell function combineFiles(file1, file2, file3, printFileCallBack) { let newFileText = '' readFile(string1, (text) => { newFileText += text readFile(string2, (text) => { newFileText += text readFile(string3, (text) => { newFileText += text printFileCallBack(newFileText) } } } }
這就很難推斷函式下面會發生什麼,同時也很難處理各種場景下發生的錯誤,比如其中某個檔案不存在的情況。
Promise 改善了這種情況
這正是 Promise 的優勢所在,Promise 是對還未產生的資料的一種推理。Kyle Simpson 將 Promise 解釋為:就像在快餐店裡點餐一樣。
- 點餐
- 為所點的午餐付費,並拿到排隊單號
- 等待午餐
- 當你的午餐準備好了,會叫你的單號提醒你取餐
- 收到午餐
正如上面的這種場景,當你等餐時,你是無法吃到午餐的,但是你可以提前為吃午餐做好準備。你可以進行其它事情,此時你知道午餐就要來了,雖然此刻你還無法享用它,但是這個午餐已經“promise”給你了。這就是所謂的 promise,表示一個最終會存在的資料的物件。
readFile(file1) .then((file1-data) => { /* do something */ }) .then((previous-promise-data) => { /* do the next thing */ }) .catch( /* handle errors */ )
上面是 Promise 語法。它主要的優點就是可以將佇列事件以一種直觀的方式連結在一起。雖然這個示例清晰易懂,但是還是用到了回撥。Promise 只是讓回撥顯得比較簡單和更加直觀。
最佳方式:async / await
若干年前,async 函式納入了 JavaScript 生態系統。就在上個月,async 函式成為了 JavaScript 語言的官方特性,並得到了廣泛支援。
async 和 await 是建立在 Promise 和 generator上。本質上,允許我們使用 await 這個關鍵詞在任何函式中的任何我們想要的地方進行暫停。
async function logger() { // pause until fetch returns let data = await fetch('') console.log(data) }
上面這段程式碼執行之後,得到了想要的結果。程式碼從 API 呼叫中記錄了資料。
這種方式的好處就是非常直觀。編寫程式碼的方式就是大腦思考的方式,告訴指令碼在需要的地方暫停。
另一個好處是,當我們不能使用 promise 時,還可以使用 try 和 catch:
async function logger () { try { let user_id = await fetch('/api/users/username') let posts = await fetch('/api/`${user_id}`') let object = JSON.parse(user.posts.toString()) console.log(posts) } catch (error) { console.error('Error:', error) } }
上面是一個刻意寫錯的示例,為了證明了一點:在執行過程中,catch 可以捕獲任何步驟中發生的錯誤。至少有三個地方,try 可能會失敗,這是在非同步程式碼中的一種最乾淨的方式來處理錯誤。
我們還可以使用帶有迴圈和條件的 async 函式:
async function count() { let counter = 1 for (let i = 0; i < 100; i++) { counter += 1 console.log(counter) await sleep(1000) } }
這是一個很簡答的例子,如果執行這段程式,將會看到程式碼在 sleep 呼叫時暫停,下一個迴圈迭代將會在1秒後啟動。
要點和細節
相信我們已經感受到了 asyns 和 await 的美妙之處,接下來讓我們深入瞭解一下細節:
- async 和 await 建立在 Promise 之上。使用 async,總是會返回一個 Promise。請記住這一點,因為這也是容易犯錯的地方。
- 當執行到 await 時,程式會暫停當前函式,而不是所有程式碼
- async 和 await 是非阻塞的
- 依舊可以使用 Promise helpers,例如 Promise.all( )
正如之前的示例:
async function logPosts () { try { let user_id = await fetch('/api/users/username') let post_ids = await fetch('/api/posts/<code>${user_id}') let promises = post_ids.map(post_id => { return fetch('/api/posts/${post_id}') } let posts = await Promise.all(promises) console.log(posts) } catch (error) { console.error('Error:', error) } }
- await 只能用於宣告為 async 的函式中
- 因此,不能在全域性範圍內使用 await
如下程式碼:
// throws an error function logger (callBack) { console.log(await callBack) } // works! async function logger () { console.log(await callBack) }
現已正式可用
到2017年6月,幾乎所有瀏覽器都可以使用 async 和 await。為了確保你的程式碼隨時可用,則需要使用 Babel 將你的 JavaScript 程式碼編譯為舊瀏覽器也支援的語法。
如果對更多ES2017內容感興趣,請訪問。
JavaScript 開發工具推薦
純前端表格控制元件是基於 HTML5 的 Java 電子表格和網格功能控制元件,提供了完備的公式引擎、排序、過濾、輸入控制元件、資料視覺化、Excel 匯入/匯出等功能,適用於 .NET、Java 和移動端等各平臺線上編輯類 Excel 功能的表格程式開發。
原文連結:
轉載請註明出自:葡萄城控制元件
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28298702/viewspace-2143866/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ES2017 非同步函式現已正式可用非同步函式
- keepalived 高可用(非搶佔式)
- zan正式開源,非同步+非阻塞的PHP框架非同步PHP框架
- lua非全域性函式函式
- SQLite 3.38.0 現已正式釋出SQLite
- ORACLE函式介紹第四篇 非著名函式之聚合函式Oracle函式
- ORACLE函式介紹第二篇 非著名函式之單值函式Oracle函式
- ORACLE函式介紹第七篇 非著名函式之分析函式Oracle函式
- 阿里雲盤正式版已釋出!現已正式支援檔案分享!阿里
- [譯] 建構函式已死,建構函式萬歲!函式
- DRBD物理同步方式實現MySQL之高可用MySql
- (函式)實現strstr函式函式
- Generator函式非同步應用函式非同步
- 非同步操作系列之Generator函式與Async函式非同步函式
- Keepalived+Nginx高可用案例(搶佔式與非搶佔式)Nginx
- Jquery庫的一些可用函式jQuery函式
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 同步、非同步、阻塞、非阻塞非同步
- 函式式的 Promise 對非同步的抽象函式Promise非同步抽象
- 非同步之三:Async 函式的使用及簡單實現非同步函式
- python中非同步非阻塞如何實現Python非同步
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步、非同步、阻塞和非阻塞非同步
- 非線性支援向量機 與核函式函式
- DRBD+ CoroSync + PaceMaker實現 MySQL之高可用(物理同步)ROSMySql
- JavaScript 定時器函式非同步原理JavaScript定時器函式非同步
- JavaScript 非同步函式的 Promisification 處理JavaScript非同步函式
- MySQL怎麼利用函式和觸發器實現非主鍵自增?MySql函式觸發器
- [轉]阻塞/非阻塞與同步/非同步非同步
- 同步與非同步 阻塞與非阻塞非同步
- Unity 編輯器現已正式面向 Linux 推出UnityLinux
- JavaEE8最終規範現已正式推出Java
- (十一)KPCA非線性降維與核函式PCA函式
- java同步非阻塞IOJava