async函數(shù)的基本用法

1. async函數(shù)的基本形式

//函數(shù)聲明asyncfunction foo() {}//函數(shù)表達式const foo = asyncfunction () {};//對象的方法let obj = { async foo() {} };

obj.foo().then(...)//Class 的方法class Storage {

constructor() {

? ? this.cachePromise = caches.open('avatars');

}

async getAvatar(name) {

? ? const cache = awaitthis.cachePromise;

? ? returncache.match(`/avatars/${name}.jpg`);

}

}

const storage =new Storage();

storage.getAvatar('jake').then(…);//箭頭函數(shù)const foo = async () => {};

2. async函數(shù)的返回值總是一個Promise

無論async函數(shù)有無await操作,其總是返回一個Promise。

1. 沒有顯式return呕诉,相當于return Promise.resolve(undefined);

2. return非Promise的數(shù)據(jù)data,相當于return Promise.resolve(data);

3. return Promise, 會得到Promise對象本身

async總是返回Promise泽谨,因此兔毒,其后面可以直接調(diào)用then方法咖楣,

函數(shù)內(nèi)部return返回的值等龙,會成為then回調(diào)函數(shù)的參數(shù)

函數(shù)內(nèi)部拋出的錯誤处渣,會被then的第二個函數(shù)或catch方法捕獲到

//正常返回值asyncfunction f(){

? ? retrun 'hello world';

}

f().then(v => console.log(v));//hello world//拋出錯誤asyncfunction f(){

? ? thrownewError('出錯了');

}

f().then(

? ? v => console.log(v),

? ? e => console.log(e)//Error: 出錯了)

3. await操作符的值

[rv] = await expression(expression可以是任何值,通常是一個promise)

expression是Promise蛛砰,rv等于Promise兌現(xiàn)的值罐栈,若Promise被拒絕,則拋出異常泥畅,由catch捕獲

expression是非Promise荠诬,會被轉換為立即resolve的Promise,rv等于expression

await操作只能用在async函數(shù)中位仁,否則會報錯柑贞。

4. async就是generator和promise的語法糖

//generator寫法vargen =function* () {

? varf1 = yield readFile('/etc/fstab');

? varf2 = yield readFile('/etc/shells');

? console.log(f1.toString());

? console.log(f2.toString());

};//async寫法varasyncReadFile = asyncfunction () {

? varf1 = await readFile('/etc/fstab');

? varf2 = await readFile('/etc/shells');

? console.log(f1.toString());

? console.log(f2.toString());

};

async就是將 generator的 * 換成 async,將 yield 換成 await聂抢。

5. async對generator的改進

1. 內(nèi)置執(zhí)行器

Generator必須依靠執(zhí)行器調(diào)用next方法來自動執(zhí)行钧嘶,例如co模塊。而async函數(shù)自帶執(zhí)行器琳疏,可以自動執(zhí)行康辑。

2. 更好的語義

async和await分別表示異步和等待摄欲,語義更加明確

3. 適用性更強

co模塊后面只能是Thunk函數(shù)或Promise對象轿亮,而await后面可以是Promise或基本數(shù)據(jù)類型(如:數(shù)字疮薇,字符串,布爾等)

4. 返回Promise我注,可以繼續(xù)操作

async函數(shù)總是返回一個Promise對象按咒,可以對其進行then調(diào)用,繼續(xù)操作后面的數(shù)據(jù)但骨,因此励七,

async函數(shù)完全可以看作是多個Promise合成一個Promise對象,而await命令就是內(nèi)部的then調(diào)用奔缠。

6. async內(nèi)部的并行調(diào)用

async配合await都是串行調(diào)用掠抬,但是若有并行調(diào)用,則應按照以下方式來寫:

1. 變量分別接收Promise

let fooPromise = getFoo();

let barPromise = getBar();

let foo = await fooPromise();

let bar = await barPromise();

2. 使用Promise.all

let [foo,bar] = await Promise.all([getFoo(),getBar()]);

Promise.all這種寫法有缺陷校哎,一個調(diào)用報錯两波,會終止,這個不太符合并行調(diào)用的初衷闷哆。

3. 使用多個async函數(shù)

實際上腰奋,一個async函數(shù)內(nèi)部包含的調(diào)用應該是強相關的,沒有依賴關系的函數(shù)調(diào)用不應該放在一個async函數(shù)中抱怔,分開來邏輯更清晰劣坊。

4. 并行執(zhí)行的一些寫法

1. 不能再內(nèi)部非async function中使用await

asyncfunction dbFuc(db) {

? let docs = [{}, {}, {}];

? // 報錯,forEach的function是非async屈留,不能使用awaitdocs.forEach(function (doc) {

? ? await db.post(doc);

? });

}//這里不需要 asyncfunction dbFuc(db) {

? let docs = [{}, {}, {}];

? // 可能得到錯誤結果局冰,這樣調(diào)用也不能得到正確的結果docs.forEach(asyncfunction (doc) {

? ? await db.post(doc);

? });

}

2. 循環(huán)調(diào)用await可以使用for循環(huán)或for of循環(huán)

//for ofasyncfunction dbFuc(db) {

? let docs = [{}, {}, {}];

? for (let doc of docs) {

? ? await db.post(doc);

? }

}//map + Promise.allasyncfunction dbFuc(db) {

? let docs = [{}, {}, {}];

? let promises = docs.map((doc) => db.post(doc));

? let results = await Promise.all(promises);

? console.log(results);

}//map + for ofasyncfunction dbFuc(db) {

? let docs = [{}, {}, {}];

? let promises = docs.map((doc) => db.post(doc));

? let results = [];

? for (let promise of promises) {

? ? results.push(await promise);

? }

? console.log(results);

}//for循環(huán)中去請求網(wǎng)頁,若await操作成功灌危,會break退出康二;若失敗,會catch捕獲乍狐,進入下一輪循環(huán)const superagent = require('superagent');

const NUM_RETRIES = 3;

async function test() {

? let i;

? for(i = 0; i < NUM_RETRIES; ++i) {

? ? try {

? ? ? await superagent.get('http://google.com/this-throws-an-error');

? ? ? break;

? ? } catch(err) {}

? }

? console.log(i); // 3}

test();

7. async的錯誤處理

使用try...catch進行包裹赠摇,例如:

asyncfunction myFunction() {

? ? try {

? ? ? ? await somethingThatReturnsAPromise();

? ? } catch (err) {

? ? ? ? console.log(err);

? ? }

}

如果僅僅對一部分錯誤進行處理或者忽略,可以局部的進行包裹浅蚪,或者對單獨的promise進行catch藕帜,例如:

asyncfunction myFunction() {

? ? await somethingThatReturnsAPromise().catch((err)=> {

? ? ? ? ? ? console.log(err);

? ? })

}

async function myFunction() {

? ? try{

? ? ? ? await somethingThatReturnsAPromise();

? ? }

? ? catch(e){}

? ? await somethingElse();

}

Promise的錯誤處理,推薦用async + await來寫:

// 存值createData(title, successBack, errorBack) {

? ? // 使用key保存數(shù)據(jù)? ? storage.save({

? ? ? ? key: title,?

? ? ? ? data: 'true',

? ? }).then(successBack(), errorBack());

}

改寫為

//存值async createData1(title, successBack, errorBack) {

? ? try {

? ? ? ? // 使用key保存數(shù)據(jù)? ? ? ? await storage.save({

? ? ? ? ? ? key: title,?

? ? ? ? ? ? data: 'true',

? ? ? ? });

? ? ? ? successBack()

? ? } catch (e) {

? ? ? ? errorBack()

? ? }

}

形式上更加清晰一些惜傲。

8. async函數(shù)的實現(xiàn)原理

async函數(shù)就是將執(zhí)行器和Generator做為一個整體返回洽故。

asyncfunction fn(){}//等同于function fn(){

? ? returnspawn(function* (){

? ? })

}

spawn的實現(xiàn)

function spawn(genF) {

? ? /****

? ? * 返回的是一個promise

? ? */returnnewPromise(function(resolve, reject) {

? ? ? ? vargen=genF();//運行Generator這個方法;/***

? ? ? ? * 執(zhí)行下一步的方法

? ? ? ? * @param fn 一個調(diào)用Generator方法的next方法

? ? ? ? */function step(fn) {

? ? ? ? ? ? //如果有錯誤盗誊,則直接返回时甚,不執(zhí)行下面的awaittry {

? ? ? ? ? ? varnext=fn();

? ? ? ? ? ? }catch (e){

? ? ? ? ? ? return reject(e)

? ? ? ? ? ? }

? ? ? ? ? ? //如果下面沒有yield語句隘弊,即Generator的done是trueif(next.done){

? ? ? ? ? ? return resolve(next.value);

? ? ? ? ? ? }

? ? ? ? ? ? Promise.resolve(next.value).then((val)=>{

? ? ? ? ? ? ? ? step(function(){return gen.next(val) } )

? ? ? ? ? ? }).catch((e)=>{

? ? ? ? ? ? ? ? step(function(){returngen.throw(e) } )

? ? ? ? ? ? })

? ? ? ? }

? ? ? ? step(function () {

? ? ? ? ? ? return gen.next();

? ? ? ? })

? ? });

}

參考自async的基本用法 - 看風景就 - 博客園

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市荒适,隨后出現(xiàn)的幾起案子梨熙,更是在濱河造成了極大的恐慌,老刑警劉巖刀诬,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咽扇,死亡現(xiàn)場離奇詭異,居然都是意外死亡陕壹,警方通過查閱死者的電腦和手機质欲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糠馆,“玉大人嘶伟,你說我怎么就攤上這事∮致担” “怎么了九昧?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赠橙。 經(jīng)常有香客問我耽装,道長,這世上最難降的妖魔是什么期揪? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任掉奄,我火速辦了婚禮,結果婚禮上凤薛,老公的妹妹穿的比我還像新娘姓建。我一直安慰自己,他們只是感情好缤苫,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布速兔。 她就那樣靜靜地躺著,像睡著了一般活玲。 火紅的嫁衣襯著肌膚如雪涣狗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天舒憾,我揣著相機與錄音镀钓,去河邊找鬼。 笑死镀迂,一個胖子當著我的面吹牛丁溅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播探遵,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窟赏,長吁一口氣:“原來是場噩夢啊……” “哼妓柜!你這毒婦竟也來了?” 一聲冷哼從身側響起涯穷,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤棍掐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后求豫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塌衰,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年蝠嘉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杯巨。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚤告,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出服爷,到底是詐尸還是另有隱情杜恰,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布仍源,位于F島的核電站心褐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏笼踩。R本人自食惡果不足惜逗爹,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嚎于。 院中可真熱鬧掘而,春花似錦、人聲如沸于购。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肋僧。三九已至斑胜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嫌吠,已是汗流浹背止潘。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留居兆,地道東北人覆山。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像泥栖,于是被迫代替她去往敵國和親簇宽。 傳聞我的和親對象是個殘疾皇子勋篓,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354