在本文中,你將學習如何使用Node.js中的async函數(async/await)來簡化callback或Promise.
異步語言結構在其他語言中已經存在了,像c#的async/await、Kotlin的coroutines、go的goroutines,隨著Node.js 8的發布,期待已久的async函數也在其中默認實現了。
Node中的async函數是什么?
當函數聲明為一個Async函數它會返回一個 AsyncFunction 對象,它們類似于 Generator 因為執可以被暫停。唯一的區別是它們返回的是 Promise 而不是 { value: any, done: Boolean } 對象。不過它們還是非常相似,你可以使用 co 包來獲取同樣的功能。
在async函數中,可以等待 Promise 完成或捕獲它拒絕的原因。
如果你要在Promise中實現一些自己的邏輯的話
function handler (req, res) { return request('https://user-handler-service') .catch((err) => { logger.error('Http error', err) error.logged = true throw err }) .then((response) => Mongo.findOne({ user: response.body.user })) .catch((err) => { !error.logged && logger.error('Mongo error', err) error.logged = true throw err }) .then((document) => executeLogic(req, res, document)) .catch((err) => { !error.logged && console.error(err) res.status(500).send() })}可以使用 async/await 讓這個代碼看起來像同步執行的代碼
async function handler (req, res) { let response try { response = await request('https://user-handler-service') } catch (err) { logger.error('Http error', err) return res.status(500).send() } let document try { document = await Mongo.findOne({ user: response.body.user }) } catch (err) { logger.error('Mongo error', err) return res.status(500).send() } executeLogic(document, req, res)}在老的v8版本中,如果有有個 promise 的拒絕沒有被處理你會得到一個警告,可以不用創建一個拒絕錯誤監聽函數。然而,建議在這種情況下退出你的應用程序。因為當你不處理錯誤時,應用程序處于一個未知的狀態。
process.on('unhandledRejection', (err) => { console.error(err) process.exit(1)})async函數模式
在處理異步操作時,有很多例子讓他們就像處理同步代碼一樣。如果使用 Promise 或 callbacks 來解決問題時需要使用很復雜的模式或者外部庫。
當需要再循環中使用異步獲取數據或使用 if-else 條件時就是一種很復雜的情況。
指數回退機制
使用 Promise 實現回退邏輯相當笨拙
function requestWithRetry (url, retryCount) { if (retryCount) { return new Promise((resolve, reject) => { const timeout = Math.pow(2, retryCount) setTimeout(() => { console.log('Waiting', timeout, 'ms') _requestWithRetry(url, retryCount) .then(resolve) .catch(reject) }, timeout) }) } else { return _requestWithRetry(url, 0) }}function _requestWithRetry (url, retryCount) { return request(url, retryCount) .catch((err) => { if (err.statusCode && err.statusCode >= 500) { console.log('Retrying', err.message, retryCount) return requestWithRetry(url, ++retryCount) } throw err })}requestWithRetry('http://localhost:3000') .then((res) => { console.log(res) }) .catch(err => { console.error(err) })
新聞熱點
疑難解答
圖片精選