首頁 >web前端 >js教程 >Node.js中如何使用async函數

Node.js中如何使用async函數

小云云
小云云原創
2018-01-18 10:19:401535瀏覽

借助新版 V8 引擎,Node.js 從 7.6 開始支援 async 函式特性。今年 10 月 31 日,Node.js 8 也開始成為新的長期支援版本,因此你完全可以放心大膽地在你的程式碼中使用 async 函數了。在這邊文章裡,我會簡單地介紹什麼是 async 函數,以及它會如何改變我們寫 Node.js 應用的方式。

1 什麼是 async 函數

利用 async 函數,你可以把基於 Promise 的非同步程式碼寫得就像同步程式碼一樣。一旦你使用 async 關鍵字定義了一個函數,那你就可以在這個函數內使用 await 關鍵字。當一個 async 函數被呼叫時,它會傳回一個 Promise。當這個 async 函數回傳一個值時,那個 Promise 就會被實作;而如果函數中拋出一個錯誤,那麼 Promise 就會被拒絕。

await 關鍵字可以被用來等待一個 Promise 被解決並傳回其實現的值。如果傳給 await 的值不是一個 Promise,那麼它會把這個值轉換成一個已解決的 Promise。


const rp = require('request-promise')
async function main () {
 const result = await rp('https://google.com')
 const twenty = await 20
 
 // 睡个1秒钟
 await new Promise (resolve => {
  setTimeout(resolve, 1000)
 })
 return result
}
main()
 .then(console.log)
 .catch(console.error)

2 向async 函數遷移

#如果你的Node.js 應用程式已經在使用Promise,那你只需要把原先的鍊式呼叫改寫為對你的這些Promise 進行await。

如果你的應用程式還在使用回呼函數,那你應該以漸進的方式轉向使用 async 函數。你可以在開發一些新功能的時候使用這項新技術。當你必須呼叫一些舊有的程式碼時,你可以簡單地把它們包裹成為 Promise 再用新的方式呼叫。

要做到這一點,你可以使用內建的util.promisify方法:


#
const util = require('util')
const {readFile} = require('fs')
const readFileAsync = util.promisify(readFile)
async function main () {
 const result = await readFileAsync('.gitignore')
 return result
}
main()
 .then(console.log)
 .catch(console.error)

3 Async 函數的最佳實踐

3.1 在express 中使用async 函數

express 本來就支援Promise,所以在express 中使用async 函數是比較簡單的:


#
const express = require('express')
const app = express()
app.get('/', async (request, response) => {
 // 在这里等待 Promise
 // 如果你只是在等待一个单独的 Promise,你其实可以直接将将它作为返回值返回,不需要使用 await 去等待。
 const result = await getContent()
 response.send(result)
})
app.listen(process.env.PORT)

但正如Keith Smith 所指出的,上面這個例子有一個嚴重的問題——如果Promise 最終被拒絕,由於這裡沒有進行錯誤處理,那麼這個express 路由處理器就會被掛起。

為了修正這個問題,你應該把你的非同步處理器包裹在一個對錯誤進行處理的函數中:


const awaitHandlerFactory = (middleware) => {
 return async (req, res, next) => {
  try {
   await middleware(req, res, next)
  } catch (err) {
   next(err)
  }
 }
}
// 然后这样使用:
app.get('/', awaitHandlerFactory(async (request, response) => {
 const result = await getContent()
 response.send(result)
}))

3.2 並行執行

比如說你正在寫這樣一個程序,一個操作需要兩個輸入,其中一個來自於資料庫,另一個則來自於一個外部服務:


async function main () {
 const user = await Users.fetch(userId)
 const product = await Products.fetch(productId)
 await makePurchase(user, product)
}

在這個例子中,會發生什麼事?

你的程式碼會先去取得 user,
然後取得 product,
最後再進行付款。
如你所見,由於前兩步驟之間並沒有相互依賴關係,其實你完全可以將它們並行執行。這裡,你應該使用Promise.all 方法:


async function main () {
 const [user, product] = await Promise.all([
  Users.fetch(userId),
  Products.fetch(productId)
 ])
 await makePurchase(user, product)
}

而有時候,你只需要其中最快被解決的Promise 的回傳值-這時,你可以使用Promise.race 方法。

3.3 錯誤處理

考慮下面這個範例:


async function main () {
 await new Promise((resolve, reject) => {
  reject(new Error('error'))
 })
}
main()
 .then(console.log)

當執行這段程式碼的時候,你會看到類似這樣的資訊:

(node:69738) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: error
(node:69738) [DEP0018] Depreise prejection Inject the Unarejection future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

在較新的Node.js 版本中,如果Promise 被拒絕且未得到處理,整個Node.js 程序就會中斷。因此必要的時候你應該使用 try-catch:


const util = require('util')
async function main () {
 try {
  await new Promise((resolve, reject) => {
   reject(new Error('

以上是Node.js中如何使用async函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn