今天就跟大家聊聊有關(guān)怎么用Async函數(shù)簡化異步代碼,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)服務(wù)項目包括江華網(wǎng)站建設(shè)、江華網(wǎng)站制作、江華網(wǎng)頁制作以及江華網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,江華網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到江華省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
Promise 在 JavaScript 上發(fā)布之初就在互聯(lián)網(wǎng)上流行了起來, 它們幫開發(fā)人員擺脫了回調(diào)地獄,解決了在很多地方困擾 JavaScript 開發(fā)者的異步問題。
隨著 ES6 的到來(現(xiàn)在被稱作 ES2015),除了引入 Promise 的規(guī)范,不需要請求那些數(shù)不盡的庫之外,我們還有了生成器。生成器可在函數(shù)內(nèi)部停止執(zhí)行,這意味著可把它們封裝在一個多用途的函數(shù)中,我們可在代碼移動到下一行之前等待異步操作完成。突然你的異步代碼可能就開始看起來同步了。
這只是第一步。異步函數(shù)因今年加入 ES2017,已進行標(biāo)準(zhǔn)化,本地支持也進一步優(yōu)化。異步函數(shù)的理念是使用生成器進行異步編程,并給出他們自己的語義和語法。因此,你無須使用庫來獲取封裝的實用函數(shù),因為這些都會在后臺處理。
運行文章中的 async/await 實例,你需要一個能兼容的瀏覽器。
運行兼容
在客戶端,Chrome、Firefox 和 Opera 能很好地支持異步函數(shù)。
從 7.6 版本開始,Node.js 默認(rèn)啟用 async/await。
異步函數(shù)和生成器對比
這有個使用生成器進行異步編程的實例,用的是 Q 庫:
var doAsyncOp = Q.async(function* () { var val = yield asynchronousOperation(); console.log(val); return val; });
Q.async 是個封裝函數(shù),處理場景后的事情。其中 * 表示作為一個生成器函數(shù)的功能,yield 表示停止函數(shù),并用封裝函數(shù)代替。Q.async 將會返回一個函數(shù),你可對它賦值,就像賦值 doAsyncOp 一樣,隨后再調(diào)用。
ES7 中的新語法更簡潔,操作示例如下:
async function doAsyncOp () { var val = await asynchronousOperation(); console.log(val); return val; };
差異不大,我們刪除了一個封裝的函數(shù)和 * 符號,轉(zhuǎn)而用 async 關(guān)鍵字代替。yield 關(guān)鍵字也被 await 取代。這兩個例子事實上做的事是相同的:在 asynchronousOperation 完成之后,賦值給 val,然后進行輸出并返回結(jié)果。
將 Promises 轉(zhuǎn)換成異步函數(shù)
如果我們使用 Vanilla Promises 的話前面的示例將會是什么樣?
function doAsyncOp () { return asynchronousOperation().then(function(val) { console.log(val); return val; }); };
這里有相同的代碼行數(shù),但這是因為 then 和給它傳遞的回調(diào)函數(shù)增加了很多的額外代碼。另一個讓人厭煩的是兩個 return 關(guān)鍵字。這一直有些事困擾著我,因為它很難弄清楚使用 promises 的函數(shù)確切的返回是什么。
就像你看到的,這個函數(shù)返回一個 promises,將會賦值給 val,猜一下生成器和異步函數(shù)示例做了什么!無論你在這個函數(shù)返回了什么,你其實是暗地里返回一個 promise 解析到那個值。如果你根本就沒有返回任何值,你暗地里返回的 promise 解析為 undefined。
鏈?zhǔn)讲僮?/strong>
Promise 之所以能受到眾人追捧,其中一個方面是因為它能以鏈?zhǔn)秸{(diào)用的方式把多個異步操作連接起來,避免了嵌入形式的回調(diào)。不過 async 函數(shù)在這個方面甚至比 Promise 做得還好。
下面演示了如何使用 Promise 來進行鏈?zhǔn)讲僮?我們只是簡單的多次運行 asynchronousOperation 來進行演示)。
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 語句中都不需要使用 await,因為用或不用,它都返回了包含了可處理終值的 Promise。
并發(fā)操作
Promise 還有另一個偉大的特性,它們可以同時進行多個異步操作,等他們?nèi)客瓿芍笤倮^續(xù)進行其它事件。ES2015 規(guī)范中提供了 Promise.all(),就是用來干這個事情的。
這里有一個示例:
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 可以通過一個函數(shù)來處理,這個處理函數(shù)要傳遞給 then,作為其第二個參數(shù),或者傳遞給 catch 方法。現(xiàn)在我們沒有使用 Promise API 中的方法,應(yīng)該怎么處理拒絕?可以通過 try 和 catch 來處理。使用 async 函數(shù)的時候,拒絕被當(dāng)作錯誤來傳遞,這樣它們就可以通過 JavaScript 本身支持的錯誤處理代碼來處理。
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嗨?,只是把它?**一環(huán)改成了調(diào)用 catch。如果用 async 函數(shù)來寫,會像下面這樣。
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)換那樣簡潔,但是確實跟寫同步代碼一樣。如果你在這里不捕捉錯誤,它會延著調(diào)用鏈一直向上拋出,直到在某處被捕捉處理。如果它一直未被捕捉,它最終會中止程序并拋出一個運行時錯誤。Promise 以同樣的方式運作,只是拒絕不必當(dāng)作錯誤來處理;它們可能只是一個說明錯誤情況的字符串。如果你不捕捉被創(chuàng)建為錯誤的拒絕,你會看到一個運行時錯誤,不過如果你只是使用一個字符串,會失敗卻不會有輸出。
中斷 Promise
拒絕原生的 Promise,只需要使用 Promise 構(gòu)建函數(shù)中的 reject 就好,當(dāng)然也可以直接拋出錯誤——在 Promise 的構(gòu)造函數(shù)中,在 then 或 catch 的回調(diào)中拋出都可以。如果是在其它地方拋出錯誤,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"); }); }
一般來說,***使用 new Error,因為它會包含錯誤相關(guān)的其它信息,比如拋出位置的行號,以及可能會有用的調(diào)用棧。
這里有一些拋出 Promise 不能捕捉的錯誤的示例:
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 中拋出錯誤就不會產(chǎn)生有關(guān)范圍的問題——你可以在 async 函數(shù)中隨時隨地拋出錯誤,它總會被 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)不會運行到 doAsyncOp 中的第二個錯誤,也不會運行到 return 語句,因為在那之前拋出的錯誤已經(jīng)中止了函數(shù)運行。
問題
如果你剛開始使用 async 函數(shù),需要小心嵌套函數(shù)的問題。比如,如果你的 async 函數(shù)中有另一個函數(shù)(通常是回調(diào)),你可能認(rèn)為可以在其中使用 await ,但實際不能。你只能直接在 async 函數(shù)中使用 await 。
比如,這段代碼無法運行:
async function getAllFiles(fileNames) { return Promise.all( fileNames.map(function(fileName) { var file = await getFileAsync(fileName); return parse(file); }) ); }
第 4 行的 await 無效,因為它是在一個普通函數(shù)中使用的。不過可以通過為回調(diào)函數(shù)添加 async 關(guān)鍵字來解決這個問題。
async function getAllFiles(fileNames) { return Promise.all( fileNames.map(async function(fileName) { var file = await getFileAsync(fileName); return parse(file); }) ); }
你看到它的時候會覺得理所當(dāng)然,即便如此,仍然需要小心這種情況。
也許你還想知道等價的使用 Promise 的代碼:
function getAllFiles(fileNames) { return Promise.all( fileNames.map(function(fileName) { return getFileAsync(fileName).then(function(file) { return parse(file); }); }) ); }
接下來的問題是關(guān)于把 async 函數(shù)看作同步函數(shù)。需要記住的是,async 函數(shù)內(nèi)部的的代碼是同步運行的,但是它會立即返回一個 Promise,并繼續(xù)運行外面的代碼,比如:
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
你會看到 async 函數(shù)實際使用了內(nèi)置的 Promise。這讓我們思考 async 函數(shù)中的同步行為,其它人可以通過普通的 Promise API 調(diào)用我們的 async 函數(shù),也可以使用它們自己的 async 函數(shù)來調(diào)用。
即使你本身不能使用異步代碼,你也可以進行編寫或使用工具將其編譯為 ES5。 異步函數(shù)能讓代碼更易于閱讀,更易于維護。 只要我們有 source maps,我們可以隨時使用更干凈的 ES2017 代碼。
有許多可以將異步功能(和其他 ES2015+功能)編譯成 ES5 代碼的工具。 如果您使用的是 Babel,這只是安裝 ES2017 preset 的例子。
看完上述內(nèi)容,你們對怎么用Async函數(shù)簡化異步代碼有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。
網(wǎng)站名稱:怎么用Async函數(shù)簡化異步代碼
分享鏈接:http://jinyejixie.com/article14/ggiige.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、網(wǎng)站導(dǎo)航、網(wǎng)站內(nèi)鏈、小程序開發(fā)、微信公眾號、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)