摘要:總結(jié)這篇文章簡單的介紹了一些常用的異步編程的方法,如果有錯誤或不嚴(yán)謹(jǐn)?shù)牡胤剑瑲g迎批評指正,如果喜歡,歡迎點贊收藏。
大家都知道js的執(zhí)行環(huán)境是單線程的,如果沒有異步編程,那么js的執(zhí)行效率會非常低下,導(dǎo)致程序十分卡頓,一提到異步編程大家首先的想到的一定是回調(diào)函數(shù),這也是最常用的異步編程的形式,但其實常用的還有Promise和Async函數(shù),接下來就讓我們一起學(xué)習(xí)這幾種常用的異步編程方法。
回調(diào)函數(shù)回調(diào)函數(shù)就是把任務(wù)的第二段多帶帶寫在一個函數(shù)里面,等到重新執(zhí)行這個任務(wù)的時候,就直接調(diào)用這個函數(shù),來看一個簡單的例子:
function print(name, callback) { setTimeout(() => { console.log(name) if (callback) { callback() } }, 1000) } print("a", function () { print("b") })
上面這個例子中將print("b")放在print("a")的回調(diào)函數(shù)中,這樣就能按順序依次打印a、b,但是回調(diào)函數(shù)有一個很明顯的問題,就是當(dāng)回調(diào)函數(shù)嵌套過深時,會導(dǎo)致代碼混亂,不夠清晰,這就是人們常說的對調(diào)地獄,來看下面這個例子:
function print(name, callback) { setTimeout(() => { console.log(name) if (callback) { callback() } }, 1000) } print("a", function () { print("b", function () { print("c", function () { print("d") }) }) })
當(dāng)我們想按順序依次打印a、b、c、d時,代碼就變成上面的樣子,可以看到,我們的代碼形成四層嵌套,如果還要加回調(diào)函數(shù)就要繼續(xù)嵌套,這樣嵌套會越寫越深,越來越難以維護,此時我們就必須考慮用新的技術(shù)去改進,es6的Promise函數(shù)應(yīng)運而生,接下來讓我們看Promise函數(shù)是如何改進這個問題的。
Promisefunction print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve() }, 1000) }) } print("a").then(() => { return print("b") }) .then(() => { return print("c") }) .then(() => { return print("d") })
和之前用回調(diào)函數(shù)的形式相比,Promise函數(shù)寫法更加清晰,由回調(diào)函數(shù)的嵌套調(diào)用變成了鏈?zhǔn)秸{(diào)用,但是Promise也有一個很嚴(yán)重的問題就是代碼冗余,原來的任務(wù)被Promise包裝了一下,不管什么操作都是放在then函數(shù)里面,導(dǎo)致代碼的語以變差,有什么更好的解決辦法呢?如果您對Promise函數(shù)還想有更深入的了解,可以去看阮一峰老師es6入門
Async在正式使用異步函數(shù)之前,先簡單的介紹一下它的用法,async通常與await一起使用,async函數(shù)返回一個Promise對象,可以使用then方法添加回調(diào)函數(shù)。當(dāng)函數(shù)執(zhí)行的時候,一旦遇到await就會先返回,等到觸發(fā)的異步操作完成,再接著執(zhí)行函數(shù)體后面的語句。做了簡單的介紹后,接下來,我們來async函數(shù)是怎么對Promise調(diào)用優(yōu)化的??聪旅娴睦樱?/p>
function print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve() }, 1000) }) } async function test () { await print("a") await print("b") await print("c") await print("d") } test()
async函數(shù)來處理之前的問題,代碼就是上面的這個例子中所展示的樣子,是不是感覺代碼瞬間清晰了,而且代碼更加好理解了,再仔細思考一下使用async異步函數(shù)就很完美了嗎?其實async異步函數(shù)也有其固有的問題,接下來我們就看看async異步函數(shù)還有什么問題需要解決。
錯誤捕獲異步函數(shù)第一個需要解決的問題就是錯誤捕獲的問題,讓我們看看一般情況下async異步函數(shù)是怎么做錯誤捕獲的,來看一個例子:
function print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve() }, 1000) }) } async function test () { try { await print("a") } catch (err) { console.log(err) } } test()
當(dāng)使用上述形式的try,catch進行錯誤捕獲的時候,是不是覺得代碼和使用Promise函數(shù)時一樣啰嗦,那有沒有好的解決辦法呢?讓我們來看另外一個例子:
function print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve("a") }, 1000) }) } async function test () { let [ err, result ] = await to(print("a")) if (err) throw err return result } test()
to.js:
function to(promise, errorExt) { return promise .then(function (data) { return [null, data]; }) .catch(function (err) { if (errorExt) { Object.assign(err, errorExt); } return [err, undefined]; }); } export { to }; export default to;
上述例子中,將async異步函數(shù)的錯誤處理封裝到了一個to.js中,這里面其實只有一個簡單方法,傳入一個Promise對象,對Promise對象進行錯誤捕獲返回值,用解構(gòu)的形式獲取返回值和錯誤,這樣就不需要反復(fù)寫try catche做錯誤捕獲了。to.js是一個開源庫
異步陷阱什么是異步陷阱呢?在使用async異步函數(shù)的時候,多個異步操作是可以同時執(zhí)行,但是有await命令變成了繼發(fā)的形式了,即必須等待前一個執(zhí)行完了后一個才能執(zhí)行,還是之前的例子:
function print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve() }, 1000) }) } async function test () { await print("a") await print("b") await print("c") await print("d") } test()
假設(shè)await print("a")、await print("b")、await print("c")、await print("d")這四個操作并沒有先后的邏輯關(guān)系,可以同時執(zhí)行,那么按照上面的寫法就會導(dǎo)致前一個執(zhí)行完再執(zhí)行下一個,整個執(zhí)行過程中的等待時間會有4s,但是同時執(zhí)行的等待時間就只有1s,這是在使用async異步函數(shù)會經(jīng)常忽略的一個問題,那么怎么解決呢?介紹一個我經(jīng)常使用的辦法,看例子:
function print(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name) resolve("a") }, 1000) }) } async function test () { Promise.all([print("a"), print("b"), print("c"), print("d")]) } test()
其實解決辦法很簡單就是通過Promise.all()方法,將所有異步操作作為參數(shù)數(shù)組傳入,這樣print("a")、print("b")、print("c")、print("d")這四個異步操作就可以并發(fā)執(zhí)行了。
總結(jié)這篇文章簡單的介紹了一些常用的異步編程的方法,如果有錯誤或不嚴(yán)謹(jǐn)?shù)牡胤?,歡迎批評指正,如果喜歡,歡迎點贊收藏。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/98835.html
摘要:學(xué)習(xí)開發(fā),無論是前端開發(fā)還是都避免不了要接觸異步編程這個問題就和其它大多數(shù)以多線程同步為主的編程語言不同的主要設(shè)計是單線程異步模型。由于異步編程可以實現(xiàn)非阻塞的調(diào)用效果,引入異步編程自然就是順理成章的事情了。 學(xué)習(xí)js開發(fā),無論是前端開發(fā)還是node.js,都避免不了要接觸異步編程這個問題,就和其它大多數(shù)以多線程同步為主的編程語言不同,js的主要設(shè)計是單線程異步模型。正因為js天生的與...
摘要:異步編程在傳統(tǒng)編程實踐中,大多數(shù)操作都是同步發(fā)生的。中的異步編程異步是一種輸入輸出處理的形式,它允許在傳輸完成之前,其它處理能繼續(xù)進行。 本文轉(zhuǎn)載自:眾成翻譯譯者:網(wǎng)絡(luò)埋伏紀(jì)事鏈接:http://www.zcfy.cc/article/1759原文:https://blog.risingstack.com/node-hero-async-programming-in-node-js/ ...
摘要:四異步編程解決方案模式模式一定程度上緩解了嵌套回調(diào)的問題,只會處在未完成完成態(tài)失敗態(tài)中的一種,只會從未完成轉(zhuǎn)化為完成態(tài)或者失敗態(tài),不能逆轉(zhuǎn)。 一、從一個簡單的案例開始 fs.readdir(path.join(__dirname, ./index.js), (err, files) => { files.foreach((filename, index) => { ...
摘要:下面我將介紹的基本用法以及如何在異步編程中使用它們。在沒有發(fā)布之前,作為異步編程主力軍的回調(diào)函數(shù)一直被人詬病,其原因有太多比如回調(diào)地獄代碼執(zhí)行順序難以追蹤后期因代碼變得十分復(fù)雜導(dǎo)致無法維護和更新等,而的出現(xiàn)在很大程度上改變了之前的窘境。 前言 自己著手準(zhǔn)備寫這篇文章的初衷是覺得如果想要更深入的理解 JS,異步編程則是必須要跨過的一道坎。由于這里面涉及到的東西很多也很廣,在初學(xué) JS 的...
摘要:為了降低異步編程的復(fù)雜性,所以。難理解請參考的誤區(qū)以及實踐異步編程的模式異步編程的種方法 異步編程 javascript異步編程, web2.0時代比較熱門的編程方式,我們平時碼的時候也或多或少用到,最典型的就是異步ajax,發(fā)送異步請求,綁定回調(diào)函數(shù),請求響應(yīng)之后調(diào)用指定的回調(diào)函數(shù),沒有阻塞其他代碼的執(zhí)行。還有像setTimeout方法同樣也是異步執(zhí)行回調(diào)的方法。 如果對異步編程...
閱讀 2012·2021-11-15 18:09
閱讀 903·2021-09-06 15:13
閱讀 2645·2021-08-23 09:43
閱讀 2026·2019-08-30 15:54
閱讀 2219·2019-08-30 13:56
閱讀 2486·2019-08-26 11:31
閱讀 3081·2019-08-26 10:56
閱讀 705·2019-08-26 10:28