摘要:本周精讀內(nèi)容是逃離地獄。精讀仔細(xì)思考為什么會(huì)被濫用,筆者認(rèn)為是它的功能比較反直覺(jué)導(dǎo)致的。同時(shí),筆者認(rèn)為,也不要過(guò)渡利用新特性修復(fù)新特性帶來(lái)的問(wèn)題,這樣反而導(dǎo)致代碼可讀性下降。
本周精讀內(nèi)容是 《逃離 async/await 地獄》。
1 引言終于,async/await 也被吐槽了。Aditya Agarwal 認(rèn)為 async/await 語(yǔ)法讓我們陷入了新的麻煩之中。
其實(shí),筆者也早就覺(jué)得哪兒不對(duì)勁了,終于有個(gè)人把實(shí)話說(shuō)了出來(lái),async/await 可能會(huì)帶來(lái)麻煩。
2 概述下面是隨處可見(jiàn)的現(xiàn)代化前端代碼:
(async () => { const pizzaData = await getPizzaData(); // async call const drinkData = await getDrinkData(); // async call const chosenPizza = choosePizza(); // sync call const chosenDrink = chooseDrink(); // sync call await addPizzaToCart(chosenPizza); // async call await addDrinkToCart(chosenDrink); // async call orderItems(); // async call })();
await 語(yǔ)法本身沒(méi)有問(wèn)題,有時(shí)候可能是使用者用錯(cuò)了。當(dāng) pizzaData 與 drinkData 之間沒(méi)有依賴時(shí),順序的 await 會(huì)最多讓執(zhí)行時(shí)間增加一倍的 getPizzaData 函數(shù)時(shí)間,因?yàn)?getPizzaData 與 getDrinkData 應(yīng)該并行執(zhí)行。
回到我們吐槽的回調(diào)地獄,雖然代碼比較丑,帶起碼兩行回調(diào)代碼并不會(huì)帶來(lái)阻塞。
看來(lái)語(yǔ)法的簡(jiǎn)化,帶來(lái)了性能問(wèn)題,而且直接影響到用戶體驗(yàn),是不是值得我們反思一下?
正確的做法應(yīng)該是先同時(shí)執(zhí)行函數(shù),再 await 返回值,這樣可以并行執(zhí)行異步函數(shù):
(async () => { const pizzaPromise = selectPizza(); const drinkPromise = selectDrink(); await pizzaPromise; await drinkPromise; orderItems(); // async call })();
或者使用 Promise.all 可以讓代碼更可讀:
(async () => { Promise.all([selectPizza(), selectDrink()]).then(orderItems); // async call })();
看來(lái)不要隨意的 await,它很可能讓你代碼性能降低。
3 精讀仔細(xì)思考為什么 async/await 會(huì)被濫用,筆者認(rèn)為是它的功能比較反直覺(jué)導(dǎo)致的。
首先 async/await 真的是語(yǔ)法糖,功能也僅是讓代碼寫(xiě)的舒服一些。先不看它的語(yǔ)法或者特性,僅從語(yǔ)法糖三個(gè)字,就能看出它一定是局限了某些能力。
舉個(gè)例子,我們利用 html 標(biāo)簽封裝了一個(gè)組件,帶來(lái)了便利性的同時(shí),其功能一定是 html 的子集。又比如,某個(gè)輪子哥覺(jué)得某個(gè)組件 api 太復(fù)雜,于是基于它封裝了一個(gè)語(yǔ)法糖,我們多半可以認(rèn)為這個(gè)便捷性是犧牲了部分功能換來(lái)的。
功能完整度與使用便利度一直是相互博弈的,很多框架思想的不同開(kāi)源版本,幾乎都是把功能完整度與便利度按照不同比例混合的結(jié)果。
那么回到 async/await 它的解決的問(wèn)題是回調(diào)地獄帶來(lái)的災(zāi)難:
a(() => { b(() => { c(); }); });
為了減少嵌套結(jié)構(gòu)太多對(duì)大腦造成的沖擊,async/await 決定這么寫(xiě):
await a(); await b(); await c();
雖然層級(jí)上一致了,但邏輯上還是嵌套關(guān)系,這不是另一個(gè)程度上增加了大腦負(fù)擔(dān)嗎?而且這個(gè)轉(zhuǎn)換還是隱形的,所以許多時(shí)候,我們傾向于忽略它,所以造成了語(yǔ)法糖的濫用。
理解語(yǔ)法糖雖然要正確理解 async/await 的真實(shí)效果比較反人類,但為了清爽的代碼結(jié)構(gòu),以及防止寫(xiě)出低性能的代碼,還是挺有必要認(rèn)真理解 async/await 帶來(lái)的改變。
首先 async/await 只能實(shí)現(xiàn)一部分回調(diào)支持的功能,也就是僅能方便應(yīng)對(duì)層層嵌套的場(chǎng)景。其他場(chǎng)景,就要?jiǎng)右恍┠X子了。
比如兩對(duì)回調(diào):
a(() => { b(); }); c(() => { d(); });
如果寫(xiě)成下面的方式,雖然一定能保證功能一致,但變成了最低效的執(zhí)行方式:
await a(); await b(); await c(); await d();
因?yàn)榉g成回調(diào),就變成了:
a(() => { b(() => { c(() => { d(); }); }); });
然而我們發(fā)現(xiàn),原始代碼中,函數(shù) c 可以與 a 同時(shí)執(zhí)行,但 async/await 語(yǔ)法會(huì)讓我們傾向于在 b 執(zhí)行完后,再執(zhí)行 c。
所以當(dāng)我們意識(shí)到這一點(diǎn),可以優(yōu)化一下性能:
const resA = a(); const resC = c(); await resA; b(); await resC; d();
但其實(shí)這個(gè)邏輯也無(wú)法達(dá)到回調(diào)的效果,雖然 a 與 c 同時(shí)執(zhí)行了,但 d 原本只要等待 c 執(zhí)行完,現(xiàn)在如果 a 執(zhí)行時(shí)間比 c 長(zhǎng),就變成了:
a(() => { d(); });
看來(lái)只有完全隔離成兩個(gè)函數(shù):
(async () => { await a(); b(); })(); (async () => { await c(); d(); })();
或者利用 Promise.all:
async function ab() { await a(); b(); } async function cd() { await c(); d(); } Promise.all([ab(), cd()]);
這就是我想表達(dá)的可怕之處。回調(diào)方式這么簡(jiǎn)單的過(guò)程式代碼,換成 async/await 居然寫(xiě)完還要反思一下,再反推著去優(yōu)化性能,這簡(jiǎn)直比回調(diào)地獄還要可怕。
而且大部分場(chǎng)景代碼是非常復(fù)雜的,同步與 await 混雜在一起,想捋清楚其中的脈絡(luò),并正確優(yōu)化性能往往是很困難的。但是我們?yōu)槭裁匆约和诳釉偬羁幽兀亢芏鄷r(shí)候還會(huì)導(dǎo)致忘了填。
原文作者給出了 Promise.all 的方式簡(jiǎn)化邏輯,但筆者認(rèn)為,不要一昧追求 async/await 語(yǔ)法,在必要情況下適當(dāng)使用回調(diào),是可以增加代碼可讀性的。
4 總結(jié)async/await 回調(diào)地獄提醒著我們,不要過(guò)渡依賴新特性,否則可能帶來(lái)的代碼執(zhí)行效率的下降,進(jìn)而影響到用戶體驗(yàn)。同時(shí),筆者認(rèn)為,也不要過(guò)渡利用新特性修復(fù)新特性帶來(lái)的問(wèn)題,這樣反而導(dǎo)致代碼可讀性下降。
當(dāng)我翻開(kāi) redux 剛火起來(lái)那段時(shí)期的老代碼,看到了許多過(guò)渡抽象、為了用而用的代碼,硬是把兩行代碼能寫(xiě)完的邏輯,拆到了 3 個(gè)文件,分散在 6 行不同位置,我只好用字符串搜索的方式查找線索,最后發(fā)現(xiàn)這個(gè)抽象代碼整個(gè)項(xiàng)目?jī)H用了一次。
寫(xiě)出這種代碼的可能性只有一個(gè),就是在精神麻木的情況下,一口氣喝完了 redux 提供的全部雞湯。
就像 async/await 地獄一樣,看到這種 redux 代碼,我覺(jué)得遠(yuǎn)不如所謂沒(méi)跟上時(shí)代的老前端寫(xiě)出的 jquery 代碼。
決定代碼質(zhì)量的是思維,而非框架或語(yǔ)法,async/await 雖好,但也要適度哦。
5 更多討論討論地址是:精讀《逃離 async/await 地獄》 · Issue #82 · dt-fe/weekly
如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/94778.html
摘要:前端進(jìn)階進(jìn)階構(gòu)建項(xiàng)目一配置最佳實(shí)踐狀態(tài)管理之痛點(diǎn)分析與改良開(kāi)發(fā)中所謂狀態(tài)淺析從時(shí)間旅行的烏托邦,看狀態(tài)管理的設(shè)計(jì)誤區(qū)使用更好地處理數(shù)據(jù)愛(ài)彼迎房源詳情頁(yè)中的性能優(yōu)化從零開(kāi)始,在中構(gòu)建時(shí)間旅行式調(diào)試用輕松管理復(fù)雜狀態(tài)如何把業(yè)務(wù)邏輯這個(gè)故事講好和 前端進(jìn)階 webpack webpack進(jìn)階構(gòu)建項(xiàng)目(一) Webpack 4 配置最佳實(shí)踐 react Redux狀態(tài)管理之痛點(diǎn)、分析與...
摘要:標(biāo)準(zhǔn)引入了函數(shù),使得異步操作變得更加方便。在異步處理上,函數(shù)就是函數(shù)的語(yǔ)法糖。在實(shí)際項(xiàng)目中,錯(cuò)誤處理邏輯可能會(huì)很復(fù)雜,這會(huì)導(dǎo)致冗余的代碼。的出現(xiàn)使得就可以捕獲同步和異步的錯(cuò)誤。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。 async ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。 在異步處理上,async 函數(shù)就是 Generator 函數(shù)的語(yǔ)法糖。 ...
摘要:引言本周精讀的文章是,講了如何利用實(shí)現(xiàn)串行執(zhí)行??偨Y(jié)串行隊(duì)列一般情況下用的不多,因?yàn)榇袝?huì)阻塞,而用戶交互往往是并行的。更多討論討論地址是精讀用實(shí)現(xiàn)串行執(zhí)行如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 本周精讀的文章是 why-using-reduce-to-sequentially-resolve-promises-works,講了如何利用 reduce...
摘要:本周精讀內(nèi)容是重新思考。數(shù)據(jù)流對(duì)數(shù)據(jù)緩存,性能優(yōu)化,開(kāi)發(fā)體驗(yàn)優(yōu)化都有進(jìn)一步施展的空間,擁抱插件生態(tài)是一個(gè)良好的發(fā)展方向。 本周精讀內(nèi)容是 《重新思考 Redux》。 1 引言 《重新思考 Redux》是 rematch 作者 Shawn McKay 寫(xiě)的一篇干貨軟文。 dva 之后,有許多基于 redux 的狀態(tài)管理框架,但大部分都很局限,甚至是倒退。但直到看到了 rematch,總算...
摘要:更好的安全性隨著的發(fā)布,從升級(jí)到了,更安全且更易配置。通過(guò)使用,程序可以減少握手所需時(shí)間來(lái)提升請(qǐng)求性能。提供診斷報(bào)告有一項(xiàng)實(shí)驗(yàn)功能,根據(jù)用戶需求提供診斷報(bào)告,包括崩潰性能下降內(nèi)存泄露使用高等等。前端精讀幫你篩選靠譜的內(nèi)容。 1. 引言 Node12 發(fā)布有幾個(gè)月了,讓我們跟隨 Nodejs 12 一起看看 Node12 帶來(lái)了哪些改變。 2. 概述 Node12 與以往的版本不同,帶來(lái)...
閱讀 4023·2021-11-11 10:58
閱讀 3426·2021-09-26 09:46
閱讀 1975·2019-08-30 15:55
閱讀 1037·2019-08-30 13:52
閱讀 2047·2019-08-29 13:11
閱讀 3082·2019-08-29 11:27
閱讀 1568·2019-08-26 18:18
閱讀 2723·2019-08-23 14:17