摘要:想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳博客一年百來篇優(yōu)質(zhì)文章等著你引入的在的異步編程中是一個(gè)極好的改進(jìn)。可能會(huì)產(chǎn)生誤導(dǎo)一些文章將與進(jìn)行了比較,并聲稱它是下一代異步編程風(fēng)格,對(duì)此作者深表異議。結(jié)論引入的關(guān)鍵字無疑是對(duì)異步編程的改進(jìn)。
想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!
ES8 引入的 async/await 在 JavaScript 的異步編程中是一個(gè)極好的改進(jìn)。它提供了使用同步樣式代碼異步訪問 resoruces 的方式,而不會(huì)阻塞主線程。然而,它們也存在一些坑及問題。在本文中,將從不同的角度探討 async/await,并演示如何正確有效地使用這對(duì)兄弟。
前置知識(shí) async 作用是什么從 MDN 可以看出:
async 函數(shù)返回的是一個(gè) Promise 對(duì)象。async 函數(shù)(包含函數(shù)語句、函數(shù)表達(dá)式、Lambda表達(dá)式)會(huì)返回一個(gè) Promise 對(duì)象,如果在函數(shù)中 return 一個(gè)直接量,async 會(huì)把這個(gè)直接量通過 Promise.resolve() 封裝成 Promise 對(duì)象。
如果 async 函數(shù)沒有返回值, 它會(huì)返回 Promise.resolve(undefined)。
await 作用是什么從 MDN 了解到:
await 等待的是一個(gè)表達(dá)式,這個(gè)表達(dá)式的計(jì)算結(jié)果是 Promise 對(duì)象或者其它值(換句話說,await 可以等任意表達(dá)式的結(jié)果)。
如果它等到的不是一個(gè) Promise 對(duì)象,那 await 表達(dá)式的運(yùn)算結(jié)果就是它等到的東西。
如果它等到的是一個(gè) Promise 對(duì)象,await 就忙起來了,它會(huì)阻塞后面的代碼,等著 Promise 對(duì)象 resolve,然后得到 resolve 的值,作為 await 表達(dá)式的運(yùn)算結(jié)果。
這就是 await 必須用在 async 函數(shù)中的原因。async 函數(shù)調(diào)用不會(huì)造成阻塞,它內(nèi)部所有的阻塞都被封裝在一個(gè) Promise 對(duì)象中異步執(zhí)行。async/await 的優(yōu)點(diǎn)
async/await 帶給我們的最重要的好處是同步編程風(fēng)格。讓我們看一個(gè)例子:
很明顯,async/await 版本比 promise 版本更容易理解。如果忽略 await 關(guān)鍵字,代碼看起來就像任何其他同步語言,比如 Python。
最佳的地方不僅在于可讀性。async/await 到今天為止,所有主流瀏覽器都完全支持異步功能。
本地瀏覽器的支持意味著你不必轉(zhuǎn)換代碼。更重要的是,它便于調(diào)試。當(dāng)在函數(shù)入口點(diǎn)設(shè)置斷點(diǎn)并跨過 await 行時(shí),將看到調(diào)試器在 bookModel.fetchAll() 執(zhí)行其任務(wù)時(shí)暫停片刻,然后它將移動(dòng)到下一個(gè).filter 行,這比 promise 代碼要簡(jiǎn)單得多,在 promise 中,必須在 .filter 行上設(shè)置另一個(gè)斷點(diǎn)。
另一個(gè)不太明顯的優(yōu)點(diǎn)是 async 關(guān)鍵字。 async聲明 getBooksByAuthorWithAwait()函數(shù)返回值確保是一個(gè) promise,因此調(diào)用者可以安全地使用 getBooksByAuthorWithAwait().then(...) 或await getBooksByAuthorWithAwait()。 想想下面的例子(不好的做法!):
在上述代碼中,getBooksByAuthorWithPromise 可能返回 promise(正常情況下)或 null 值(異常情況下),在異常情況下,調(diào)用者不能調(diào)用 .then()。有了async 聲明,這種情況就不會(huì)出現(xiàn)了。
async/await 可能會(huì)產(chǎn)生誤導(dǎo)一些文章將 async/wait 與 Promise 進(jìn)行了比較,并聲稱它是 JavaScript 下一代異步編程風(fēng)格,對(duì)此作者深表異議。async/await 是一種改進(jìn),但它只不過是一種語法糖,不會(huì)完全改變我們的編程風(fēng)格。
從本質(zhì)上說,async 函數(shù)仍然是 promise。在正確使用 async 函數(shù)之前,你必須先了解 promise,更糟糕的是,大多數(shù)時(shí)候你需要在使用 promises 的同時(shí)使用 async 函數(shù)。
考慮上面示例中的 getBooksByAuthorWithAwait() 和getbooksbyauthorwithpromise() 函數(shù)。請(qǐng)注意,它們不僅功能相同,而且具有完全相同的接口!
這意味著 getbooksbyauthorwithwait() 將返回一個(gè) promise,所以也可以使用 .then(...)方式來調(diào)用它。
嗯,這未必是件壞事。只有 await 的名字給人一種感覺,“哦,太好了,可以把異步函數(shù)轉(zhuǎn)換成同步函數(shù)了”,這實(shí)際上是錯(cuò)誤的。
async/await那么在使用 async/await 時(shí)可能會(huì)犯什么錯(cuò)誤呢?下面是一些常見的例子。
太過串行化盡管 await 可以使代碼看起來像是同步的,但實(shí)際它們?nèi)匀皇钱惒降模仨毿⌒谋苊馓^串行化。
上述代碼在邏輯上看似正確的,然而,這是錯(cuò)誤的。
await bookModel.fetchAll() 會(huì)等待 fetchAll() 直到 fetchAll() 返回結(jié)果。
然后 await authorModel.fetch(authorId) 被調(diào)用。
注意,authorModel.fetch(authorId) 并不依賴于 bookModel.fetchAll() 的結(jié)果,實(shí)際上它們可以并行調(diào)用!然而,用了 await,兩個(gè)調(diào)用變成串行的,總的執(zhí)行時(shí)間將比并行版本要長(zhǎng)得多得多。
下面是正確的方式:
更糟糕的是,如果你想要一個(gè)接一個(gè)地獲取項(xiàng)目列表,你必須依賴使用 promises:
簡(jiǎn)而言之,你仍然需要將流程視為異步的,然后使用 await 寫出同步的代碼。在復(fù)雜的流程中,直接使用 promise 可能更方便。
錯(cuò)誤處理在 promise中,異步函數(shù)有兩個(gè)可能的返回值: resolved 和 rejected。我們可以用 .then() 處理正常情況,用 .catch() 處理異常情況。然而,使用 async/await方式的,錯(cuò)誤處理可能比較棘手。
try…catch最標(biāo)準(zhǔn)的(也是作者推薦的)方法是使用 try...catch 語法。在 await 調(diào)用時(shí),在調(diào)用 await 函數(shù)時(shí),如果出現(xiàn)非正常狀況就會(huì)拋出異常,await 命令后面的 promise 對(duì)象,運(yùn)行結(jié)果可能是 rejected,所以最好把await 命令放在 try...catch 代碼塊中。如下例子:
在捕捉到異常之后,有幾種方法來處理它:
處理異常,并返回一個(gè)正常值。(不在 catch 塊中使用任何 return 語句相當(dāng)于使用 return undefined,undefined 也是一個(gè)正常值。)
如果你想讓調(diào)用者處理它,你可以直接拋出普通的錯(cuò)誤對(duì)象,如 throw errorr,它允許你在 promise 鏈中使用 async getBooksByAuthorWithAwait() 函數(shù)(也就是說,可以像getBooksByAuthorWithAwait().then(...).catch(error => ...) 處理錯(cuò)誤); 或者可以用 Error 對(duì)象將錯(cuò)誤封裝起來,如 throw new Error(error),當(dāng)這個(gè)錯(cuò)誤在控制臺(tái)中顯示時(shí),它將給出完整的堆棧跟蹤信息。
拒絕它,就像 return Promise.reject(error) ,這相當(dāng)于 throw error,所以不建議這樣做。
使用 try...catch 的好處:
簡(jiǎn)單,傳統(tǒng)。只要有Java或c++等其他語言的經(jīng)驗(yàn),理解這一點(diǎn)就不會(huì)有任何困難。
如果不需要每步執(zhí)行錯(cuò)誤處理,你仍然可以在一個(gè) try ... catch 塊中包裝多個(gè) await 調(diào)用來處理一個(gè)地方的錯(cuò)誤。
這種方法也有一個(gè)缺陷。由于 try...catch 會(huì)捕獲代碼塊中的每個(gè)異常,所以通常不會(huì)被 promise 捕獲的異常也會(huì)被捕獲到。比如:
運(yùn)行此代碼,你將得到一個(gè)錯(cuò)誤 ReferenceError: cb is not defined。這個(gè)錯(cuò)誤是由console.log()打印出來的的,而不是 JavaScript 本身。有時(shí)這可能是致命的:如果 BookModel 被包含在一系列函數(shù)調(diào)用中,其中一個(gè)調(diào)用者吞噬了錯(cuò)誤,那么就很難找到這樣一個(gè)未定義的錯(cuò)誤。
讓函數(shù)返回兩個(gè)值另一種錯(cuò)誤處理方法是受到Go語言的啟發(fā)。它允許異步函數(shù)返回錯(cuò)誤和結(jié)果。詳情請(qǐng)看這篇博客文章:
How to write async await without try-catch blocks in Javascript
簡(jiǎn)而言之,你可以像這樣使用異步函數(shù):
[err, user] = await to(UserModel.findById(1));
作者個(gè)人不喜歡這種方法,因?yàn)樗鼘?Go 語言的風(fēng)格帶入到了 JavaScript 中,感覺不自然。但在某些情況下,這可能相當(dāng)有用。
使用 .catch這里介紹的最后一種方法就是繼續(xù)使用 .catch()。
回想一下 await 的功能:它將等待 promise 完成它的工作。值得注意的一點(diǎn)是 promise.catch() 也會(huì)返回一個(gè) promise ,所以我們可以這樣處理錯(cuò)誤:
這種方法有兩個(gè)小問題:
它是 promises 和 async 函數(shù)的混合體。你仍然需要理解 是promises 如何工作的。
錯(cuò)誤處理先于正常路徑,這是不直觀的。
結(jié)論ES7引入的 async/await 關(guān)鍵字無疑是對(duì)J avaScrip t異步編程的改進(jìn)。它可以使代碼更容易閱讀和調(diào)試。然而,為了正確地使用它們,必須完全理解 promise,因?yàn)?async/await 只不過是 promise 的語法糖,本質(zhì)上仍然是 promise。
原文:
https://hackernoon.com/javasc...
你的點(diǎn)贊是我持續(xù)分享好東西的動(dòng)力,歡迎點(diǎn)贊!
交流干貨系列文章匯總?cè)缦拢X得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。
https://github.com/qq44924588...
我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!
關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/100635.html
摘要:普通的回調(diào)函數(shù)調(diào)用執(zhí)行后續(xù)邏輯使用了以后的復(fù)雜邏輯獲取到正確的結(jié)果輸出兩個(gè)文件拼接后的內(nèi)容雖說解決了的問題,不會(huì)出現(xiàn)一個(gè)函數(shù)前邊有二三十個(gè)空格的縮進(jìn)。所以直接使用關(guān)鍵字替換原有的普通回調(diào)函數(shù)即可。 從今年過完年回來,三月份開始,就一直在做重構(gòu)相關(guān)的事情。 就在今天剛剛上線了最新一次的重構(gòu)代碼,希望高峰期安好,接近半年的Node.js代碼重構(gòu)。 包含從callback+async.w...
摘要:到目前為止,表達(dá)這種流程的基本形式是課程。按鈕依次響應(yīng)并更改獲取更新的文本。事實(shí)證明不能從返回一個(gè)。可以在組件中使用本地狀態(tài),而無需使用類。替換了提供統(tǒng)一,和。另一方面,跟蹤中的狀態(tài)變化確實(shí)很難。 備注:為了保證的可讀性,本文采用意譯而非直譯。 在這個(gè) React鉤子 教程中,你將學(xué)習(xí)如何使用 React鉤子,它們是什么,以及我們?yōu)槭裁催@樣做! showImg(https://segm...
摘要:前言對(duì)于這門語言,其實(shí)我更喜歡稱它為,從一開始我們就已經(jīng)涉及到異步編程,但是多數(shù)開發(fā)者從來沒有認(rèn)真思考過自己程序中的異步,到底是怎么實(shí)現(xiàn)的,以及為什么會(huì)出現(xiàn)。 前言 對(duì)于JavaScript這門語言,其實(shí)我更喜歡稱它為ECMAScript,從一開始我們就已經(jīng)涉及到異步編程,但是多數(shù)JavaScript開發(fā)者從來沒有認(rèn)真思考過自己程序中的異步,到底是怎么實(shí)現(xiàn)的,以及為什么會(huì)出現(xiàn)。但是由于...
摘要:原文地址原文作者翻譯作者是在版本中引入的,它對(duì)于中的異步編程而言是一個(gè)巨大的提升。可能會(huì)產(chǎn)生誤導(dǎo)一些文章把和進(jìn)行了比較,同時(shí)說它是異步編程演變過程中的下一代解決方案,對(duì)此我不敢茍同。結(jié)論在中引入的關(guān)鍵字無疑是對(duì)異步編程的一大加強(qiáng)。 原文地址: https://hackernoon.com/javasc...原文作者: Charlee Li 翻譯作者: Xixi20160512 asy...
閱讀 1014·2021-11-22 13:52
閱讀 1448·2021-11-19 09:40
閱讀 3174·2021-11-16 11:44
閱讀 1276·2021-11-15 11:39
閱讀 3909·2021-10-08 10:04
閱讀 5367·2021-09-22 14:57
閱讀 3106·2021-09-10 10:50
閱讀 3188·2021-08-17 10:13