promise與await

解決異步編程的方法—promise與await

promise是什么蚕甥?

Promise择懂,簡(jiǎn)單說(shuō)就是一個(gè)容器哑梳,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō)袁串,Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息呼巷。Promise 提供統(tǒng)一的 API囱修,各種異步操作都可以用同樣的方法進(jìn)行處理。簡(jiǎn)單來(lái)說(shuō)王悍,promise的作用就是將異步操作以同步操作的流程表達(dá)出來(lái)破镰,避免了層層嵌套的回調(diào)函數(shù)。

promise的特點(diǎn)

① 對(duì)象的狀態(tài)不受外界影響:promise異步操作有三種狀態(tài):進(jìn)行中压储,已成功鲜漩,已失敗。只有異步操作才能改變這個(gè)狀態(tài)集惋。
②一變則不變:promise狀態(tài)一旦改變孕似,就不會(huì)再發(fā)生變化,promise對(duì)象改變的兩種可能刮刑,進(jìn)行中—>已成功喉祭,進(jìn)行中—>已失敗。

promise的基本用法

promise對(duì)象是一個(gè)構(gòu)造函數(shù)雷绢,用來(lái)生成promise實(shí)例
例子:

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

其中接受的參數(shù)是resolve和reject兩個(gè)函數(shù)
resolve的作用:將promise對(duì)象的狀態(tài)由進(jìn)行中—>已完成泛烙。并將異步操作的結(jié)果作為參數(shù)傳遞出去
rejected的作用:將promise對(duì)象的狀態(tài)由進(jìn)行中—>已失敗,并將異步失敗的原因作為參數(shù)傳遞出去习寸。
注意:調(diào)用resolve或reject并不會(huì)終結(jié)promise的參數(shù)函數(shù)的執(zhí)行
例子:

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

上面代碼調(diào)用了resolve(1)以后胶惰,后面的console(2)還是會(huì)執(zhí)行,并且會(huì)首先打印出來(lái)霞溪。這是因?yàn)榱⒓磖esolved的promise是在本輪事件循環(huán)的末尾執(zhí)行孵滞,總是晚于本輪循環(huán)的同步任務(wù)中捆。

then的用法

promise實(shí)例生成后,用then方法分別指定resolved狀態(tài)和rejucted狀態(tài)的回調(diào)函數(shù)坊饶。
例子:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)泄伪,第一個(gè)回調(diào)函數(shù)是當(dāng)promise對(duì)象狀態(tài)是resolve(已完成)的時(shí)候調(diào)用,第二個(gè)回調(diào)函數(shù)(可選)是當(dāng)promise對(duì)象狀態(tài)是reject(已失斈浼丁)的時(shí)候調(diào)用蟋滴。
如例子:

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

結(jié)果是done

鏈?zhǔn)降膖hen用法

then方法返回的是一個(gè)新的Promise實(shí)例(注意,不是原來(lái)那個(gè)Promise實(shí)例)痘绎。因此可以采用鏈?zhǔn)綄懛ń蚝磘hen方法后面再調(diào)用另一個(gè)then方法
例子

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("resolved: ", comments);
}, function funcB(err){
  console.log("rejected: ", err);
});

上面代碼中,第一個(gè)then方法指定的回調(diào)函數(shù)孤页,返回的是另一個(gè)Promise對(duì)象尔苦。這時(shí),第二個(gè)then方法指定的回調(diào)函數(shù)行施,就會(huì)等待這個(gè)新的Promise對(duì)象狀態(tài)發(fā)生變化允坚。如果變?yōu)閞esolved,就調(diào)用funcA蛾号,如果狀態(tài)變?yōu)閞ejected稠项,就調(diào)用funcB。

catch方法

promise對(duì)象中鲜结,如果異步操作拋出錯(cuò)誤展运,狀態(tài)就會(huì)變?yōu)閞ejected,就會(huì)調(diào)用catch方法指定的回調(diào)函數(shù)處理這個(gè)錯(cuò)誤精刷,另外乐疆,then方法指定的回調(diào)函數(shù),如果運(yùn)行中拋出錯(cuò)誤也會(huì)被catch方法捕獲贬养。
例子:

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

promise對(duì)象的錯(cuò)誤具有“冒泡”性質(zhì),會(huì)一直向后傳琴庵,直到被捕獲误算,也就是說(shuō),會(huì)跳過(guò)中間的then函數(shù)
例子:

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 處理前面三個(gè)Promise產(chǎn)生的錯(cuò)誤
});

finally方法

finally方法用于指定不管promise對(duì)象最后狀態(tài)如何迷殿,都會(huì)執(zhí)行的操作儿礼。
例子:

server.listen(port)
  .then(function () {
    // ...
  })
  .finally(server.stop);

例子是服務(wù)器使用promise處理請(qǐng)求,然后使用finally()方法關(guān)掉服務(wù)器庆寺。

promise.all()方法

promise.all方法用于將多個(gè)promise實(shí)例蚊夫,包裝成一個(gè)新的promise實(shí)例。
比如:const p = Promise.all([p1, p2, p3]);
Promise.all方法懦尝,接受的是一個(gè)數(shù)組作為參數(shù)知纷,其中的元素都是promise實(shí)例壤圃,如果不是,則會(huì)自動(dòng)將參數(shù)轉(zhuǎn)變?yōu)閜romie實(shí)例琅轧。
p的狀態(tài)是有它的數(shù)組里面的元素決定的伍绳,分兩種狀態(tài)(用上面舉例)
①只有p1 p2 p3的狀態(tài)都變成fulfilled(已完成)的狀態(tài)才會(huì)變成fulfilled(已完成),此時(shí)p1 p2 p3的返回值組成一個(gè)數(shù)組乍桂,傳遞給p的回調(diào)函數(shù)冲杀。
②只有p1 p2 p3之中,有一個(gè)被rejucted(未完成)睹酌,p的狀態(tài)就會(huì)變成rejected(未完成)权谁,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)憋沿。
例子:
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
throw new Error('報(bào)錯(cuò)了');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 報(bào)錯(cuò)了enter code here
代碼中旺芽,因?yàn)閜2報(bào)錯(cuò)了,所會(huì)執(zhí)行promise,all的catch方法

promise.race()方法

Promise.race方法同樣是將多個(gè) Promise 實(shí)例卤妒,包裝成一個(gè)新的 Promise 實(shí)例

const p = Promise.race([p1, p2, p3]);

如果p1 p2 p3不是promise實(shí)例甥绿,也會(huì)自動(dòng)轉(zhuǎn)變成promise實(shí)例
與promise.all不同的是,上面代碼中则披,只用p1共缕、p2、p3之中有一個(gè)實(shí)例率先改變狀態(tài)士复,p的狀態(tài)就跟著改變图谷。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調(diào)函數(shù)阱洪。


async函數(shù)是什么

async的引入便贵,使得異步操作變得更加方便,那async函數(shù)是什么冗荸,其實(shí)它是Generator函數(shù)的語(yǔ)法糖承璃。使異步函數(shù)、回調(diào)函數(shù)在語(yǔ)法上看上去更像同步函數(shù)蚌本。Generator這里就不介紹了盔粹。我們直接來(lái)學(xué)習(xí)async

async的基本用法

async返回值是一個(gè)promise對(duì)象,因此可以使用then方法添加回調(diào)函數(shù)程癌,當(dāng)函數(shù)執(zhí)行的時(shí)候舷嗡,一旦遇到await就會(huì)先返回,等到異步操作完成嵌莉,再接著執(zhí)行函數(shù)體內(nèi)后面的內(nèi)容进萄。
例子:

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});

async函數(shù)的使用形式

//函數(shù)聲明
async function foo(){}
//函數(shù)表達(dá)式
const foo = async function(){};
//對(duì)象的方法
let obj = {async  foo(){}};
obj.foo().then(...)
//class的方法
class Storage{
consttuctor(){
    this.cachePromise=caches.open('avatars');
    }
    async getAvatar(name){
    const cache = await this.cachePromise;
    return cache.match('/avatars/${name}.jpg')};
    }
}

const storage =new Storage();
storage.getAvatar('jake').then(....);
}
}

const storage =new Storage();
storage.getAvatar('jake').then(...)

//箭頭函數(shù)
const foo =async()=>{};

async 函數(shù)內(nèi)部return語(yǔ)句返回的值中鼠,會(huì)成為then方法調(diào)用函數(shù)的參數(shù)可婶。
例子:

async  function f(){
return ‘hello world’;
}
f().then(v=>console.log(v))
//"hello world"

async promise 對(duì)象的狀態(tài)變化

只有等到async函數(shù)內(nèi)部的一部操作執(zhí)行完兜蠕,才會(huì)執(zhí)行then方法指定的回調(diào)函數(shù)扰肌。
例子:

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"

await 命令

正常情況下,await命令后面跟著的是一個(gè)promise對(duì)象熊杨,如果不是會(huì)自動(dòng)轉(zhuǎn)化為promise對(duì)象
例子:

async function f(){
return await 123;
}
f().then(v =>console.log(v))
//123

當(dāng)一個(gè)await語(yǔ)句后面的promise變?yōu)閞eject曙旭,那么整個(gè)函數(shù)都會(huì)中斷執(zhí)行。
例子:

async function f() {
  await Promise.reject('出錯(cuò)了');
  await Promise.resolve('hello world'); // 不會(huì)執(zhí)行
}

錯(cuò)誤處理

如果await 后面的異步操作有錯(cuò)晶府,那么等同于async函數(shù)返回的promis對(duì)象被reject (上文講promise對(duì)象的時(shí)候有提到過(guò)桂躏,冒泡性質(zhì))
例子:

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('出錯(cuò)了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出錯(cuò)了

使用try ....catch代碼塊課防止出錯(cuò)。
例子:

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出錯(cuò)了');
    });
  } catch(e) {
  }
  return await('hello world');
}

也可以將多個(gè)await命令都放在try..catch結(jié)構(gòu)中

async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}

注意點(diǎn)

①await命令只能用在async函數(shù)中川陆,用在普通函數(shù)中會(huì)報(bào)錯(cuò)剂习。

詳細(xì)可以看阮一峰

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市较沪,隨后出現(xiàn)的幾起案子鳞绕,更是在濱河造成了極大的恐慌,老刑警劉巖尸曼,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件们何,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡控轿,警方通過(guò)查閱死者的電腦和手機(jī)冤竹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茬射,“玉大人鹦蠕,你說(shuō)我怎么就攤上這事≡谂祝” “怎么了钟病?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)刚梭。 經(jīng)常有香客問(wèn)我档悠,道長(zhǎng),這世上最難降的妖魔是什么望浩? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮惰说,結(jié)果婚禮上磨德,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好典挑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布酥宴。 她就那樣靜靜地躺著,像睡著了一般您觉。 火紅的嫁衣襯著肌膚如雪拙寡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天琳水,我揣著相機(jī)與錄音肆糕,去河邊找鬼。 笑死在孝,一個(gè)胖子當(dāng)著我的面吹牛诚啃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播私沮,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼始赎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了仔燕?” 一聲冷哼從身側(cè)響起造垛,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晰搀,沒(méi)想到半個(gè)月后五辽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厕隧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年奔脐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吁讨。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡髓迎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出建丧,到底是詐尸還是另有隱情排龄,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布翎朱,位于F島的核電站橄维,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拴曲。R本人自食惡果不足惜争舞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澈灼。 院中可真熱鬧竞川,春花似錦店溢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至遭贸,卻和暖如春戈咳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背壕吹。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工著蛙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人算利。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓册踩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親效拭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子暂吉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Prepending(進(jìn)行時(shí)),Resolve(成功了)缎患,Reject(失敗了)慕的,then......等 1.Pr...
    _菩提本無(wú)樹_閱讀 49,057評(píng)論 0 21
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,706評(píng)論 1 56
  • title: promise總結(jié) 總結(jié)在前 前言 下文類似 Promise#then挤渔、Promise#resolv...
    JyLie閱讀 12,244評(píng)論 1 21
  • Promise對(duì)象是一種解決異步問(wèn)題的方法肮街,還有的解決方案是asyns 和 await (es7) 這么是目前的終...
    站在大神的肩膀上看世界閱讀 1,264評(píng)論 0 6
  • 國(guó)慶節(jié)的第二天了,如果一定要形容這一天的狀態(tài)判导,就是頹廢嫉父,除了打球的那一個(gè)鐘的時(shí)間。 很難以想象眼刃,這居然會(huì)是我目...
    他坐在我對(duì)面閱讀 342評(píng)論 0 0