<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧)

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 20:23:02
        文檔

        用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧)

        用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧):Promise 在 JavaScript 上發(fā)布之初就在互聯(lián)網(wǎng)上流行了起來(lái) — 它們幫開發(fā)人員擺脫了回調(diào)地獄,解決了在很多地方困擾 JavaScript 開發(fā)者的異步問題。但 Promises 也遠(yuǎn)非完美。它們一直請(qǐng)求回調(diào),在一些復(fù)雜的問題上仍會(huì)有些雜亂和一些難以置信的冗余。隨著 E
        推薦度:
        導(dǎo)讀用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧):Promise 在 JavaScript 上發(fā)布之初就在互聯(lián)網(wǎng)上流行了起來(lái) — 它們幫開發(fā)人員擺脫了回調(diào)地獄,解決了在很多地方困擾 JavaScript 開發(fā)者的異步問題。但 Promises 也遠(yuǎn)非完美。它們一直請(qǐng)求回調(diào),在一些復(fù)雜的問題上仍會(huì)有些雜亂和一些難以置信的冗余。隨著 E
        Promise 在 JavaScript 上發(fā)布之初就在互聯(lián)網(wǎng)上流行了起來(lái) — 它們幫開發(fā)人員擺脫了回調(diào)地獄,解決了在很多地方困擾 JavaScript 開發(fā)者的異步問題。但 Promises 也遠(yuǎn)非完美。它們一直請(qǐng)求回調(diào),在一些復(fù)雜的問題上仍會(huì)有些雜亂和一些難以置信的冗余。

        隨著 ES6 的到來(lái)(現(xiàn)在被稱作 ES2015),除了引入 Promise 的規(guī)范,不需要請(qǐng)求那些數(shù)不盡的庫(kù)之外,我們還有了生成器。生成器可在函數(shù)內(nèi)部停止執(zhí)行,這意味著可把它們封裝在一個(gè)多用途的函數(shù)中,我們可在代碼移動(dòng)到下一行之前等待異步操作完成。突然你的異步代碼可能就開始看起來(lái)同步了。

        這只是第一步。異步函數(shù)因今年加入 ES2017,已進(jìn)行標(biāo)準(zhǔn)化,本地支持也進(jìn)一步優(yōu)化。異步函數(shù)的理念是使用生成器進(jìn)行異步編程,并給出他們自己的語(yǔ)義和語(yǔ)法。因此,你無(wú)須使用庫(kù)來(lái)獲取封裝的實(shí)用函數(shù),因?yàn)檫@些都會(huì)在后臺(tái)處理。

        運(yùn)行文章中的 async/await 實(shí)例,你需要一個(gè)能兼容的瀏覽器。

        運(yùn)行兼容

        在客戶端,Chrome、Firefox 和 Opera 能很好地支持異步函數(shù)。

        從 7.6 版本開始,Node.js 默認(rèn)啟用 async/await。

        異步函數(shù)和生成器對(duì)比

        這有個(gè)使用生成器進(jìn)行異步編程的實(shí)例,用的是 Q 庫(kù):

        var doAsyncOp = Q.async(function* () { 
         
         var val = yield asynchronousOperation(); 
         
         console.log(val); 
         
         return val; 
         
        });

        Q.async 是個(gè)封裝函數(shù),處理場(chǎng)景后的事情。其中 * 表示作為一個(gè)生成器函數(shù)的功能,yield 表示停止函數(shù),并用封裝函數(shù)代替。Q.async 將會(huì)返回一個(gè)函數(shù),你可對(duì)它賦值,就像賦值 doAsyncOp 一樣,隨后再調(diào)用。

        ES7 中的新語(yǔ)法更簡(jiǎn)潔,操作示例如下:

        async function doAsyncOp () { 
         
         var val = await asynchronousOperation(); 
         
         console.log(val); 
         
         return val; 
         
        };

        差異不大,我們刪除了一個(gè)封裝的函數(shù)和 * 符號(hào),轉(zhuǎn)而用 async 關(guān)鍵字代替。yield 關(guān)鍵字也被 await 取代。這兩個(gè)例子事實(shí)上做的事是相同的:在 asynchronousOperation 完成之后,賦值給 val,然后進(jìn)行輸出并返回結(jié)果。

        將 Promises 轉(zhuǎn)換成異步函數(shù)

        如果我們使用 Vanilla Promises 的話前面的示例將會(huì)是什么樣?

        function doAsyncOp () { 
         
         return asynchronousOperation().then(function(val) { 
         
         console.log(val); 
         
         return val; 
         
         }); 
         
        };

        這里有相同的代碼行數(shù),但這是因?yàn)?then 和給它傳遞的回調(diào)函數(shù)增加了很多的額外代碼。另一個(gè)讓人厭煩的是兩個(gè) return 關(guān)鍵字。這一直有些事困擾著我,因?yàn)樗茈y弄清楚使用 promises 的函數(shù)確切的返回是什么。

        就像你看到的,這個(gè)函數(shù)返回一個(gè) promises,將會(huì)賦值給 val,猜一下生成器和異步函數(shù)示例做了什么!無(wú)論你在這個(gè)函數(shù)返回了什么,你其實(shí)是暗地里返回一個(gè) promise 解析到那個(gè)值。如果你根本就沒有返回任何值,你暗地里返回的 promise 解析為 undefined。

        鏈?zhǔn)讲僮?/p>

        Promise 之所以能受到眾人追捧,其中一個(gè)方面是因?yàn)樗芤枣準(zhǔn)秸{(diào)用的方式把多個(gè)異步操作連接起來(lái),避免了嵌入形式的回調(diào)。不過(guò) async 函數(shù)在這個(gè)方面甚至比 Promise 做得還好。

        下面演示了如何使用 Promise 來(lái)進(jìn)行鏈?zhǔn)讲僮?我們只是簡(jiǎn)單的多次運(yùn)行 asynchronousOperation 來(lái)進(jìn)行演示)。

        function doAsyncOp() { 
         
         return asynchronousOperation() 
         
         .then(function(val) { 
         
         return asynchronousOperation(val); 
         
         }) 
         
         .then(function(val) { 
         
         return asynchronousOperation(val); 
         
         }) 
         
         .then(function(val) { 
         
         return asynchronousOperation(val); 
         
         }); 
         
        }

        使用 async 函數(shù),只需要像編寫同步代碼那樣調(diào)用 asynchronousOperation:

        async function doAsyncOp () { 
         
         var val = await asynchronousOperation(); 
         
         val = await asynchronousOperation(val); 
         
         val = await asynchronousOperation(val); 
         
         return await asynchronousOperation(val); 
         
        };

        甚至最后的 return 語(yǔ)句中都不需要使用 await,因?yàn)橛没虿挥茫挤祷亓税丝商幚斫K值的 Promise。

        并發(fā)操作

        Promise 還有另一個(gè)偉大的特性,它們可以同時(shí)進(jìn)行多個(gè)異步操作,等他們?nèi)客瓿芍笤倮^續(xù)進(jìn)行其它事件。ES2015 規(guī)范中提供了 Promise.all(),就是用來(lái)干這個(gè)事情的。

        這里有一個(gè)示例:

        function doAsyncOp() { 
         
         return Promise.all([ 
         
         asynchronousOperation(), 
         
         asynchronousOperation() 
         
         ]).then(function(vals) { 
         
         vals.forEach(console.log); 
         
         return vals; 
         
         }); 
         
        }

        Promise.all() 也可以當(dāng)作 async 函數(shù)使用:

        async function doAsyncOp() { 
         
         var vals = await Promise.all([ 
         
         asynchronousOperation(), 
         
         asynchronousOperation() 
         
         ]); 
         
         vals.forEach(console.log.bind(console)); 
         
         return vals; 
         
        }

        這里就算使用了 Promise.all,代碼仍然很清楚。

        處理拒絕

        Promises 可以被接受(resovled)也可以被拒絕(rejected)。被拒絕的 Promise 可以通過(guò)一個(gè)函數(shù)來(lái)處理,這個(gè)處理函數(shù)要傳遞給 then,作為其第二個(gè)參數(shù),或者傳遞給 catch 方法。現(xiàn)在我們沒有使用 Promise API 中的方法,應(yīng)該怎么處理拒絕?可以通過(guò) try 和 catch 來(lái)處理。使用 async 函數(shù)的時(shí)候,拒絕被當(dāng)作錯(cuò)誤來(lái)傳遞,這樣它們就可以通過(guò) JavaScript 本身支持的錯(cuò)誤處理代碼來(lái)處理。

        function doAsyncOp() { 
         
         return asynchronousOperation() 
         
         .then(function(val) { 
         
         return asynchronousOperation(val); 
         
         }) 
         
         .then(function(val) { 
         
         return asynchronousOperation(val); 
         
         }) 
         
         .catch(function(err) { 
         
         console.error(err); 
         
         }); 
         
        }

        這與我們鏈?zhǔn)教幚淼氖纠浅O嗨疲皇前阉淖詈笠画h(huán)改成了調(diào)用 catch。如果用 async 函數(shù)來(lái)寫,會(huì)像下面這樣。

        async function doAsyncOp () { 
         
         try { 
         
         var val = await asynchronousOperation(); 
         
         val = await asynchronousOperation(val); 
         
         return await asynchronousOperation(val); 
         
         } catch (err) { 
         
         console.err(err); 
         
         } 
         
        };

        它不像其它往 async 函數(shù)的轉(zhuǎn)換那樣簡(jiǎn)潔,但是確實(shí)跟寫同步代碼一樣。如果你在這里不捕捉錯(cuò)誤,它會(huì)延著調(diào)用鏈一直向上拋出,直到在某處被捕捉處理。如果它一直未被捕捉,它最終會(huì)中止程序并拋出一個(gè)運(yùn)行時(shí)錯(cuò)誤。Promise 以同樣的方式運(yùn)作,只是拒絕不必當(dāng)作錯(cuò)誤來(lái)處理;它們可能只是一個(gè)說(shuō)明錯(cuò)誤情況的字符串。如果你不捕捉被創(chuàng)建為錯(cuò)誤的拒絕,你會(huì)看到一個(gè)運(yùn)行時(shí)錯(cuò)誤,不過(guò)如果你只是使用一個(gè)字符串,會(huì)失敗卻不會(huì)有輸出。

        中斷 Promise

        拒絕原生的 Promise,只需要使用 Promise 構(gòu)建函數(shù)中的 reject 就好,當(dāng)然也可以直接拋出錯(cuò)誤——在 Promise 的構(gòu)造函數(shù)中,在 then 或 catch 的回調(diào)中拋出都可以。如果是在其它地方拋出錯(cuò)誤,Promise 就管不了了。

        這里有一些拒絕 Promise 的示例:

        function doAsyncOp() { 
         
         return new Promise(function(resolve, reject) { 
         
         if (somethingIsBad) { 
         
         reject("something is bad"); 
         
         } 
         
         resolve("nothing is bad"); 
         
         }); 
         
        } 
         
         
         
        /*-- or --*/ 
         
         
         
        function doAsyncOp() { 
         
         return new Promise(function(resolve, reject) { 
         
         if (somethingIsBad) { 
         
         reject(new Error("something is bad")); 
         
         } 
         
         resolve("nothing is bad"); 
         
         }); 
         
        } 
         
         
         
        /*-- or --*/ 
         
         
         
        function doAsyncOp() { 
         
         return new Promise(function(resolve, reject) { 
         
         if (somethingIsBad) { 
         
         throw new Error("something is bad"); 
         
         } 
         
         resolve("nothing is bad"); 
         
         }); 
         
        }

        一般來(lái)說(shuō),最好使用 new Error,因?yàn)樗鼤?huì)包含錯(cuò)誤相關(guān)的其它信息,比如拋出位置的行號(hào),以及可能會(huì)有用的調(diào)用棧。

        這里有一些拋出 Promise 不能捕捉的錯(cuò)誤的示例:

        function doAsyncOp() { 
         
         // the next line will kill execution 
         
         throw new Error("something is bad"); 
         
         return new Promise(function(resolve, reject) { 
         
         if (somethingIsBad) { 
         
         throw new Error("something is bad"); 
         
         } 
         
         resolve("nothing is bad"); 
         
         }); 
         
        } 
         
         
         
        // assume `doAsyncOp` does not have the killing error 
         
        function x() { 
         
         var val = doAsyncOp().then(function() { 
         
         // this one will work just fine 
         
         throw new Error("I just think an error should be here"); 
         
         }); 
         
         // this one will kill execution 
         
         throw new Error("The more errors, the merrier"); 
         
         return val; 
         
        }

        在 async 函數(shù)的 Promise 中拋出錯(cuò)誤就不會(huì)產(chǎn)生有關(guān)范圍的問題——你可以在 async 函數(shù)中隨時(shí)隨地拋出錯(cuò)誤,它總會(huì)被 Promise 抓住:

        async function doAsyncOp() { 
         
         // the next line is fine 
         
         throw new Error("something is bad"); 
         
         if (somethingIsBad) { 
         
         // this one is good too 
         
         throw new Error("something is bad"); 
         
         } 
         
         return "nothing is bad"; 
         
        } 
         
         
         
        // assume `doAsyncOp` does not have the killing error 
         
        async function x() { 
         
         var val = await doAsyncOp(); 
         
         // this one will work just fine 
         
         throw new Error("I just think an error should be here"); 
         
         return val; 
         
        }

        當(dāng)然,我們永遠(yuǎn)不會(huì)運(yùn)行到 doAsyncOp 中的第二個(gè)錯(cuò)誤,也不會(huì)運(yùn)行到 return 語(yǔ)句,因?yàn)樵谀侵皰伋龅腻e(cuò)誤已經(jīng)中止了函數(shù)運(yùn)行。

        問題

        如果你剛開始使用 async 函數(shù),需要小心嵌套函數(shù)的問題。比如,如果你的 async 函數(shù)中有另一個(gè)函數(shù)(通常是回調(diào)),你可能認(rèn)為可以在其中使用 await ,但實(shí)際不能。你只能直接在 async 函數(shù)中使用 await 。

        比如,這段代碼無(wú)法運(yùn)行:

        async function getAllFiles(fileNames) { 
         
         return Promise.all( 
         
         fileNames.map(function(fileName) { 
         
         var file = await getFileAsync(fileName); 
         
         return parse(file); 
         
         }) 
         
         ); 
         
        }

        第 4 行的 await 無(wú)效,因?yàn)樗窃谝粋€(gè)普通函數(shù)中使用的。不過(guò)可以通過(guò)為回調(diào)函數(shù)添加 async 關(guān)鍵字來(lái)解決這個(gè)問題。

        async function getAllFiles(fileNames) { 
         
         return Promise.all( 
         
         fileNames.map(async function(fileName) { 
         
         var file = await getFileAsync(fileName); 
         
         return parse(file); 
         
         }) 
         
         ); 
         
        }

        你看到它的時(shí)候會(huì)覺得理所當(dāng)然,即便如此,仍然需要小心這種情況。

        也許你還想知道等價(jià)的使用 Promise 的代碼:

        function getAllFiles(fileNames) { 
         
         return Promise.all( 
         
         fileNames.map(function(fileName) { 
         
         return getFileAsync(fileName).then(function(file) { 
         
         return parse(file); 
         
         }); 
         
         }) 
         
         ); 
         
        }

        接下來(lái)的問題是關(guān)于把 async 函數(shù)看作同步函數(shù)。需要記住的是,async 函數(shù)內(nèi)部的的代碼是同步運(yùn)行的,但是它會(huì)立即返回一個(gè) Promise,并繼續(xù)運(yùn)行外面的代碼,比如:

        var a = doAsyncOp(); // one of the working ones from earlier 
         
        console.log(a); 
         
        a.then(function() { 
         
         console.log("`a` finished"); 
         
        }); 
         
        console.log("hello"); 
         
         
         
        /* -- will output -- */ 
         
        Promise Object 
         
        hello 
         
        `a` finished

        你會(huì)看到 async 函數(shù)實(shí)際使用了內(nèi)置的 Promise。這讓我們思考 async 函數(shù)中的同步行為,其它人可以通過(guò)普通的 Promise API 調(diào)用我們的 async 函數(shù),也可以使用它們自己的 async 函數(shù)來(lái)調(diào)用。

        如今,更好的異步代碼!

        即使你本身不能使用異步代碼,你也可以進(jìn)行編寫或使用工具將其編譯為 ES5。 異步函數(shù)能讓代碼更易于閱讀,更易于維護(hù)。 只要我們有 source maps,我們可以隨時(shí)使用更干凈的 ES2017 代碼。

        有許多可以將異步功能(和其他 ES2015+功能)編譯成 ES5 代碼的工具。 如果您使用的是 Babel,這只是安裝 ES2017 preset 的例子。

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧)

        用Async函數(shù)簡(jiǎn)化異步代碼(JavaScript開發(fā)技巧):Promise 在 JavaScript 上發(fā)布之初就在互聯(lián)網(wǎng)上流行了起來(lái) — 它們幫開發(fā)人員擺脫了回調(diào)地獄,解決了在很多地方困擾 JavaScript 開發(fā)者的異步問題。但 Promises 也遠(yuǎn)非完美。它們一直請(qǐng)求回調(diào),在一些復(fù)雜的問題上仍會(huì)有些雜亂和一些難以置信的冗余。隨著 E
        推薦度:
        標(biāo)簽: 小技巧 方法 使用
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲精品无码av片| 最近中文字幕无吗高清免费视频| 欧洲亚洲国产精华液| 亚洲日韩av无码中文| 青娱乐在线视频免费观看| 久久www免费人成看国产片| 久久成人无码国产免费播放| 成人性生交视频免费观看| 久久亚洲国产成人影院| 国产真人无码作爱免费视频 | 亚洲黄色在线播放| 色五月五月丁香亚洲综合网| 免费日本一区二区| 亚洲日韩在线中文字幕第一页| 久久精品国产亚洲AV无码娇色| 在线看亚洲十八禁网站| 成人免费福利视频| 亚洲一区二区三区无码中文字幕| 波多野结衣亚洲一级| 日本在线免费观看| 亚洲人成在线中文字幕| 亚洲免费视频网站| 亚洲国产综合无码一区二区二三区 | 亚洲女同成av人片在线观看 | 啦啦啦中文在线观看电视剧免费版| 亚洲精品无码久久久影院相关影片 | 亚洲精品麻豆av| 国产好大好硬好爽免费不卡| 亚洲国产精品一区二区久| 日韩a级毛片免费观看| 亚洲av日韩av天堂影片精品| 理论秋霞在线看免费| 亚洲日韩精品射精日| 4hu四虎最新免费地址| 羞羞网站免费观看| 中文字幕亚洲综合精品一区| 免费无码黄网站在线观看| 亚洲福利一区二区| 69av免费观看| 亚洲自偷自偷精品| 国产伦精品一区二区三区免费迷 |