在Node.js中使用Async和Await函數
這篇文章主要介紹了Node.js中的Async和Await函數的相關知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
在本文中,你將學習如何使用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) })
程式碼看的讓人很頭痛,你也不會想看這樣的程式碼。我們可以使用async/await重新這個例子,使其更簡單
function wait (timeout) { return new Promise((resolve) => { setTimeout(() => { resolve() }, timeout) }) } async function requestWithRetry (url) { const MAX_RETRIES = 10 for (let i = 0; i <= MAX_RETRIES; i++) { try { return await request(url) } catch (err) { const timeout = Math.pow(2, i) console.log('Waiting', timeout, 'ms') await wait(timeout) console.log('Retrying', err.message, i) } } }
上面程式碼看起來很舒服對不對
中間值
##不像前面的例子那麼嚇人,如果你有3個非同步函數依序相互依賴的情況,那麼你必須從幾個難看的解決方案中進行選擇。 functionA 回傳一個 Promise ,那麼 functionB 需要這個值而 functioinC 需要 functionA 和 functionB 完成後的值。方案1: then 聖誕樹
function executeAsyncTask () { return functionA() .then((valueA) => { return functionB(valueA) .then((valueB) => { return functionC(valueA, valueB) }) }) }
方案2:移到上一層作用域
function executeAsyncTask () { let valueA return functionA() .then((v) => { valueA = v return functionB(valueA) }) .then((valueB) => { return functionC(valueA, valueB) }) }
方案3:使用一個多餘的陣列
function executeAsyncTask () { return functionA() .then(valueA => { return Promise.all([valueA, functionB(valueA)]) }) .then(([valueA, valueB]) => { return functionC(valueA, valueB) }) }
方案4:寫一個幫助函數
const converge = (...promises) => (...args) => { let [head, ...tail] = promises if (tail.length) { return head(...args) .then((value) => converge(...tail)(...args.concat([value]))) } else { return head(...args) } } functionA(2) .then((valueA) => converge(functionB, functionC)(valueA))
async function executeAsyncTask () { const valueA = await functionA() const valueB = await functionB(valueA) return function3(valueA, valueB) }
async function executeParallelAsyncTasks () { const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ]) doSomethingWith(valueA) doSomethingElseWith(valueB) doAnotherThingWith(valueC) }
陣列迭代方法
你可以在map 、 filter 、 reduce 方法中使用async函數,雖然它們看起來不是很直觀,但是你可以在控制台中實驗以下程式碼。 1.mapfunction asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].map(async (value) => { const v = await asyncThing(value) return v * 2 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].filter(async (value) => { const v = await asyncThing(value) return v % 2 === 0 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].reduce(async (acc, value) => { return await acc + await asyncThing(value) }, Promise.resolve(0)) } main() .then(v => console.log(v)) .catch(err => console.error(err))
解決方案:
[ Promise { <pending> }, Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ] [ 1, 2, 3, 4 ] 10
main() .then(v => Promise.all(v)) .then(v => console.log(v)) .catch(err => console.error(err)) 一开始你会等待 Promise 解决,然后使用map遍历每个值 function main () { return Promise.all([1,2,3,4].map((value) => asyncThing(value))) } main() .then(values => values.map((value) => value * 2)) .then(v => console.log(v)) .catch(err => console.error(err))
这种方式当你能拿到第一个值,就可以开始做一些计算,而不必等到所有 Promise 完成才运行你的计算。尽管结果包裹在 Promise 中,但是如果按顺序执行结果会更快。
关于 filter 的问题
你可能发觉了,即使上面filter函数里面返回了 [ false, true, false, true ] , await asyncThing(value) 会返回一个 promise 那么你肯定会得到一个原始的值。你可以在return之前等待所有异步完成,在进行过滤。
Reducing很简单,有一点需要注意的就是需要将初始值包裹在 Promise.resolve 中
重写基于callback的node应用成
Async 函数默认返回一个 Promise ,所以你可以使用 Promises 来重写任何基于 callback 的函数,然后 await 等待他们执行完毕。在node中也可以使用 util.promisify 函数将基于回调的函数转换为基于 Promise 的函数
重写基于Promise的应用程序
要转换很简单, .then 将Promise执行流串了起来。现在你可以直接使用`async/await。
function asyncTask () { return functionA() .then((valueA) => functionB(valueA)) .then((valueB) => functionC(valueB)) .then((valueC) => functionD(valueC)) .catch((err) => logger.error(err)) }
转换后
async function asyncTask () { try { const valueA = await functionA() const valueB = await functionB(valueA) const valueC = await functionC(valueB) return await functionD(valueC) } catch (err) { logger.error(err) } } Rewriting Nod
使用 Async/Await 将很大程度上的使应用程序具有高可读性,降低应用程序的处理复杂度(如:错误捕获),如果你也使用 node v8+的版本不妨尝试一下,或许会有新的收获。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在angularJs-$http中如何实现百度搜索时的动态下拉框
以上是在Node.js中使用Async和Await函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

async是es7的。 async和await是ES7中新增內容,是對於非同步操作的解決方案;async/await可以說是co模組和生成器函數的語法糖,用更清晰的語意解決js非同步程式碼。 async顧名思義是「非同步」的意思,async用於聲明一個函數是異步的;async和await有一個嚴格規定,兩者都離不開對方,且await只能寫在async函數中。

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!
