ES2017異步函數現已正式可用

ES2017標準已於2017年6月份正式定稿了,並普遍支持最新的特性:異步函數。若是你曾經被異步 JavaScript 的邏輯困擾,這麼新函數正是爲你設計的。css

異步函數或多或少會讓你編寫一些順序的 JavaScript 代碼,可是卻不須要在 callbacks、generators 或 promise 中包含你的邏輯。前端

以下代碼:api

function logger() {promise

let data = fetch('http://sampleapi.com/posts')
console.log(data)

}
logger()
這段代碼並未實現你的預期。若是你是在JS中編寫的,那麼你可能會知道爲何。瀏覽器

下面這段代碼,卻實現了你的預期。異步

async function logger() {async

let data = await fetch('http:sampleapi.com/posts')
console.log(data)

}
logger()
這段代碼起做用了,從直觀上看,僅僅只是多了 async 和 await 兩個詞。ide

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('http://sampleapi.com/posts')
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內容感興趣,請訪問ES2017特性的完整列表。

JavaScript 開發工具推薦

SpreadJS 純前端表格控件是基於 HTML5 的 Java 電子表格和網格功能控件,提供了完備的公式引擎、排序、過濾、輸入控件、數據可視化、Excel 導入/導出等功能,適用於 .NET、Java 和移動端等各平臺在線編輯類 Excel 功能的表格程序開發。

原文連接:https://css-tricks.com/using-...

轉載請註明出自:葡萄城控件

相關文章
相關標籤/搜索