javascript之異步函數

這篇文章詳細講解了JavaScript中的異步函數。 JavaScript中的異步代碼在很短的時間內從回調發展爲Promise,再到ES2017的異步函數,如今咱們能夠像編寫同步代碼那樣編寫基於 Promise 的代碼,並且還不會阻塞主線程。javascript

爲何須要async/await?

當promise在ES2015中引入時,目的是解決異步代碼的問題,可是promise不是最終的解決方案。java

雖然Promise解決了著名的回調地獄,可是它本身引入了語法複雜性。json

因此ES2017增長了異步函數,提升了代碼可讀性,對不太熟悉 Promise 的人而言,幫助就更大了。promise

async/await使代碼看起來像是同步的,但它在後臺是異步和非阻塞的。異步

工做原理

異步函數返回一個promise,以下例所示:async

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something'), 3000)
    })
}
複製代碼

調用一個異步函數時,您先要設置一個await,當您 await 某個 Promise 時,函數暫停執行,直至該 Promise 產生結果,而且暫停並不會阻塞主線程。 若是 Promise 執行,則會返回值。 若是 Promise 拒絕,則會拋出拒絕的值。由於異步函數去掉了全部回調。提升了代碼的可讀性,這是一個例子:函數

const doSomething = async () => {
    console.log(await doSomethingAsync())
}
複製代碼

一個簡單的例子

這是異步函數async / await的簡單示例:fetch

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something'), 3000)
    })
}
const doSomething = async () => {
    console.log(await doSomethingAsync())
}
console.log('Before')
doSomething()
console.log('After')
複製代碼

上面代碼執行結果以下:ui

Before
After
//after 3s
I did something 
複製代碼

Promise詳解

將async關鍵字添加到任何函數意味着該函數將返回一個promise。即便它沒有聲明,它也會在內部使它返回一個promise。 這就是此代碼有效的緣由:spa

const aFunction = async () => {
  return 'test'
}
// This will alert 'test'
 aFunction().then(alert)
複製代碼

它和如下同樣:

const aFunction = async () => {
  return Promise.resolve('test')
}
// This will alert 'test'
aFunction().then(alert) 
複製代碼

代碼更易讀

正如上面示例所見,與回調和promise代碼相比,異步函數代碼看起來很是簡單。

咱們下面用更復雜一點的代碼來演示。

例如,如下是使用promises獲取JSON資源並解析它的方法:

const getFirstUserData = () => {
    // get users list
    return fetch('/users.json') 
        // parse JSON
        .then(response => response.json()) 
        // pick first user 
        .then(users => users[0]) 
        // get user data
        .then(user => fetch(`/users/${user.name}`)) 
        // parse JSON
        .then(userResponse => response.json()) 
}
getFirstUserData() 
複製代碼

如下是使用await / async提供的相同功能:

const getFirstUserData = async () => {
    // get users list
    const response = await fetch('/users.json') 
    // parse JSON
    const users = await response.json() 
    // pick first user
    const user = users[0] 
    // get user data
    const userResponse = await fetch(`/users/${user.name}`) 
    // parse JSON
    const userData = await user.json() 
    
    return userData
}
getFirstUserData()
複製代碼

連接多個異步函數

異步函數能夠很是容易地連接,而且語法比簡單的promise更具可讀性:

const promiseToDoSomething = () => {
    return new Promise(resolve => {
        setTimeout(() => resolve('I did something'), 10000)
    })
}
const watchOverSomeoneDoingSomething = async () => {
    const something = await promiseToDoSomething()
    return something + ' and I watched'
}
const watchOverSomeoneWatchingSomeoneDoingSomething = async () => {
    const something = await watchOverSomeoneDoingSomething()
    return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {
    console.log(res)
})
複製代碼

將打印:

I did something and I watched and I watched as well
複製代碼

調試更簡單

調試promise很難,由於調試器不會debug異步代碼。 Async / await使得這很是簡單,由於編譯器就像同步代碼同樣。

相關文章
相關標籤/搜索