摘要:而函數(shù)的命令后面則可以是或者原始類型的值,,,但這時(shí)等同于同步操作返回值是。拋出的錯(cuò)誤而會(huì)被方法回調(diào)函數(shù)接收到。
ES7 提出的async 函數(shù),終于讓 JavaScript 對(duì)于異步操作有了終極解決方案。No more callback hell。
async 函數(shù)是 Generator 函數(shù)的語法糖。使用 關(guān)鍵字 async 來表示,在函數(shù)內(nèi)部使用 await 來表示異步。
想較于 Generator,Async 函數(shù)的改進(jìn)在于下面四點(diǎn):
內(nèi)置執(zhí)行器。Generator 函數(shù)的執(zhí)行必須依靠執(zhí)行器,而 Aysnc 函數(shù)自帶執(zhí)行器,調(diào)用方式跟普通函數(shù)的調(diào)用一樣
更好的語義。async 和 await 相較于 * 和 yield 更加語義化
更廣的適用性。co 模塊約定,yield 命令后面只能是 Thunk 函數(shù)或 Promise對(duì)象。而 async 函數(shù)的 await 命令后面則可以是 Promise 或者 原始類型的值(Number,string,boolean,但這時(shí)等同于同步操作)
返回值是 Promise。async 函數(shù)返回值是 Promise 對(duì)象,比 Generator 函數(shù)返回的 Iterator 對(duì)象方便,可以直接使用 then() 方法進(jìn)行調(diào)用
Async 與其他異步操作的對(duì)比先定義一個(gè) Fetch 方法用于獲取 github user 的信息:
function fetchUser() { return new Promise((resolve, reject) => { fetch("https://api.github.com/users/superman66") .then((data) => { resolve(data.json()); }, (error) => { reject(error); }) }); }
Promise 方式
/** * Promise 方式 */ function getUserByPromise() { fetchUser() .then((data) => { console.log(data); }, (error) => { console.log(error); }) } getUserByPromise();
Promise 的方式雖然解決了 callback hell,但是這種方式充滿了 Promise的 then() 方法,如果處理流程復(fù)雜的話,整段代碼將充滿 then。語義化不明顯,代碼流程不能很好的表示執(zhí)行流程。
Generator 方式
/** * Generator 方式 */ function* fetchUserByGenerator() { const user = yield fetchUser(); return user; } const g = fetchUserByGenerator(); const result = g.next().value; result.then((v) => { console.log(v); }, (error) => { console.log(error); })
Generator 的方式解決了 Promise 的一些問題,流程更加直觀、語義化。但是 Generator 的問題在于,函數(shù)的執(zhí)行需要依靠執(zhí)行器,每次都需要通過 g.next() 的方式去執(zhí)行。
async 方式
/** * async 方式 */ async function getUserByAsync(){ let user = await fetchUser(); return user; } getUserByAsync() .then(v => console.log(v));
async 函數(shù)完美的解決了上面兩種方式的問題。流程清晰,直觀、語義明顯。操作異步流程就如同操作同步流程。同時(shí) async 函數(shù)自帶執(zhí)行器,執(zhí)行的時(shí)候無需手動(dòng)加載。
語法async 函數(shù)返回一個(gè) Promise 對(duì)象
async 函數(shù)內(nèi)部 return 返回的值。會(huì)成為 then 方法回調(diào)函數(shù)的參數(shù)。
async function f() { return "hello world" }; f().then( (v) => console.log(v)) // hello world
如果 async 函數(shù)內(nèi)部拋出異常,則會(huì)導(dǎo)致返回的 Promise 對(duì)象狀態(tài)變?yōu)?reject 狀態(tài)。拋出的錯(cuò)誤而會(huì)被 catch 方法回調(diào)函數(shù)接收到。
async function e(){ throw new Error("error"); } e().then(v => console.log(v)) .catch( e => console.log(e));
async 函數(shù)返回的 Promise 對(duì)象,必須等到內(nèi)部所有的 await 命令的 Promise 對(duì)象執(zhí)行完,才會(huì)發(fā)生狀態(tài)改變
也就是說,只有當(dāng) async 函數(shù)內(nèi)部的異步操作都執(zhí)行完,才會(huì)執(zhí)行 then 方法的回調(diào)。
const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout)); async function f(){ await delay(1000); await delay(2000); await delay(3000); return "done"; } f().then(v => console.log(v)); // 等待6s后才輸出 "done"
正常情況下,await 命令后面跟著的是 Promise ,如果不是的話,也會(huì)被轉(zhuǎn)換成一個(gè) 立即 resolve 的 Promise
如下面這個(gè)例子:
async function f() { return await 1 }; f().then( (v) => console.log(v)) // 1
如果返回的是 reject 的狀態(tài),則會(huì)被 catch 方法捕獲。
Async 函數(shù)的錯(cuò)誤處理async 函數(shù)的語法不難,難在錯(cuò)誤處理上。
先來看下面的例子:
let a; async function f() { await Promise.reject("error"); a = await 1; // 這段 await 并沒有執(zhí)行 } f().then(v => console.log(a));
如上面所示,當(dāng) async 函數(shù)中只要一個(gè) await 出現(xiàn) reject 狀態(tài),則后面的 await 都不會(huì)被執(zhí)行。
解決辦法:可以添加 try/catch。
// 正確的寫法 let a; async function correct() { try { await Promise.reject("error") } catch (error) { console.log(error); } a = await 1; return a; } correct().then(v => console.log(a)); // 1
如果有多個(gè) await 則可以將其都放在 try/catch 中。
如何在項(xiàng)目中使用依然是通過 babel 來使用。
只需要設(shè)置 presets 為 stage-3 即可。
安裝依賴:
npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime
修改.babelrc:
"presets": ["es2015", "stage-3"], "plugins": ["transform-runtime"]
這樣就可以在項(xiàng)目中使用 async 函數(shù)了。
Further ReadingUnderstanding JavaScript’s async await
Async/Await - Best Practices in Asynchronous Programming
異步操作和 Async 函數(shù)
文章首發(fā)于我的博客:chenhuichao.com
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84122.html
摘要:第部分畫圖一步步看清宏任務(wù)微任務(wù)的執(zhí)行過程我們以開篇的經(jīng)典面試題為例,分析這個(gè)例子中的宏任務(wù)和微任務(wù)。注意這里只是把推入微任務(wù)隊(duì)列,并沒有執(zhí)行。執(zhí)行結(jié)束,才能繼續(xù)執(zhí)行后面的代碼如圖此時(shí)當(dāng)前宏任務(wù)都執(zhí)行完了,要處理微任務(wù)隊(duì)列里的代碼。 8張圖讓你一步步看清 async/await 和 promise 的執(zhí)行順序 為什么寫這篇文章? 測(cè)試一下自己有沒有必要看 需要具備的前置基礎(chǔ)知識(shí) 主...
摘要:因?yàn)楹瘮?shù)返回一個(gè)對(duì)象,所以可以用于等待一個(gè)函數(shù)的返回值這也可以說是在等函數(shù),但要清楚,它等的實(shí)際是一個(gè)返回值。幫我們干了啥作個(gè)簡(jiǎn)單的比較上面已經(jīng)說明了會(huì)將其后的函數(shù)函數(shù)表達(dá)式或的返回值封裝成一個(gè)對(duì)象,而會(huì)等待這個(gè)完成,并將其的結(jié)果返回出來。 隨著 Node 7 的發(fā)布,越來越多的人開始研究據(jù)說是異步編程終級(jí)解決方案的 async/await。我第一次看到這組關(guān)鍵字并不是在 JavaSc...
摘要:在異步編程中,提供了對(duì)象的方式。例如等同于所以可以理解為生成一個(gè)實(shí)例。那么自然也可以去調(diào)用則是配合使用的。等于是等待一個(gè)返回值,等待的執(zhí)行結(jié)果。但是函數(shù)不會(huì)造成阻塞,所以配合使用,則沒有影響到外部。 在異步編程中,es6提供了promise對(duì)象的方式。簡(jiǎn)單的用法 var promise = new Promise((resolve,reject)=>{ if(){ ...
摘要:所以是在一秒后顯示的。這個(gè)行為不會(huì)耗費(fèi)資源,因?yàn)橐婵梢酝瑫r(shí)處理其他任務(wù)執(zhí)行其他腳本,處理事件等。每個(gè)回調(diào)首先被放入微任務(wù)隊(duì)列然后在當(dāng)前代碼執(zhí)行完成后被執(zhí)行。,函數(shù)是異步的,但是會(huì)立即運(yùn)行。否則,就返回結(jié)果,并賦值。 「async/await」是 promises 的另一種更便捷更流行的寫法,同時(shí)它也更易于理解和使用。 Async functions 讓我們以 async 這個(gè)關(guān)鍵字開...
摘要:?jiǎn)栴}的關(guān)鍵在于其執(zhí)行過程中的微任務(wù)數(shù)量,下文中我們需要用上述代碼中的方式對(duì)微任務(wù)的執(zhí)行順序進(jìn)行標(biāo)記,以輔助我們理解這其中的執(zhí)行過程。 原文發(fā)布在掘金社區(qū):https://juejin.im/post/5c3cc981f265da616a47e028 起源 2019年了,相信大家對(duì) Promise 和 async/await 都不再陌生了。 前幾日,我在社區(qū)讀到了一篇關(guān)于 async/...
閱讀 3286·2021-11-18 10:02
閱讀 2009·2021-09-22 10:54
閱讀 3012·2019-08-30 15:43
閱讀 2603·2019-08-30 13:22
閱讀 1598·2019-08-29 13:57
閱讀 1074·2019-08-29 13:27
閱讀 772·2019-08-26 14:05
閱讀 2551·2019-08-26 13:30