promise

本文是整理阮一峰大神ES6中 Promise 的學(xué)習(xí)筆記

目錄:

  • Promise.prototype.then()
  • Promise.prototype.catch()
    模擬的是catch代碼塊
  • Promise.prototype.finally()
  • Promise.all()
    全部fulfilled或第一個rejected時回調(diào)
  • Promise.race()
    率先改變的 Promise 實例的返回值,就傳遞的回調(diào)函數(shù)
  • Promise.allSettled()
    全部結(jié)束時回調(diào)
  • Promise.any()
    有一個是fulfilled狀態(tài)账千,就是fulfilled狀態(tài)涌穆,所有都是rejected狀態(tài)募谎,才會是rejected狀態(tài)
  • Promise.resolve()
    將現(xiàn)有對象轉(zhuǎn)為 Promise 對象
  • Promise.reject()
  • Promise.try()
    模擬try代碼塊

Promise對象是一個構(gòu)造函數(shù)削祈,用來生成Promise實例

1.promise狀態(tài)狀態(tài)不受外界影響

  • pending(進行中)
  • fulfilled(已成功)resolved(已定型)
  • rejected(已失斄撼省)

2.狀態(tài)改變详瑞,就不會再變

一旦狀態(tài)改變宪祥,就不會再變,任何時候都可以得到這個結(jié)果丑掺。Promise對象的狀態(tài)改變获印,只有兩種可能:

  • 從pending變?yōu)閒ulfilled
  • 從pending變?yōu)閞ejected

3.Promise缺點

  • 無法取消Promise,一旦新建它就會立即執(zhí)行街州,無法中途取消兼丰。
  • 不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤唆缴,不會反應(yīng)到外部鳍征。
  • 當處于pending狀態(tài)時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)面徽。

4.代碼實例

// 創(chuàng)建promise實例
const promise = new Promise(function(resolve, reject) {
  // 這里的代碼創(chuàng)建后立即執(zhí)行
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
// promise.then()  接收兩個參數(shù)回調(diào)函數(shù)艳丛,成功函數(shù),失敗函數(shù)
promise.then(function(value) {
  // 全部執(zhí)行完執(zhí)行這里
  // success
}, function(error) {
  // failure
});

5.Promise對象實現(xiàn)的 Ajax 操作

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯了', error);
});

6.Promise.prototype.then()

then方法是定義在原型對象Promise.prototype上的趟紊,返回的是Promise的原型對象的新實例
Promise.prototype ——> new Promise() 原實例
Promise.prototype ——> new Promise().then() 新實例

getJSON("/post/1.json")
.then(function(post) {
  // 這里return的值將傳入下邊的then中
  return getJSON(post.commentURL); 
})
.then(function (comments) {
  // comments這里的參數(shù)就是上邊return的值
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

7.Promise.prototype.catch()

Promise.prototype.catch與下邊等同氮双,但建議用這種方法獲取報錯,因為Promise 對象的錯誤具有“冒泡”性質(zhì)霎匈,最后的catch能獲取到之前n個then中的所有報錯信息

  • .then(null, rejection)
  • .then(undefined, rejection)

異步操作拋出錯誤戴差,狀態(tài)就會變?yōu)閞ejected,就會調(diào)用catch方法指定的回調(diào)函數(shù),可以寫多個catch和多個then,順序隨意

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 會吃掉錯誤
Promise 內(nèi)部的錯誤不會影響到 Promise 外部的代碼

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行會報錯铛嘱,因為x沒有聲明
    resolve(x + 2);
  });
};

someAsyncThing().then(function() {
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123

8.Promise.prototype.finally()

  • finally方法用于指定不管 Promise 對象最后狀態(tài)如何暖释,都會執(zhí)行的操作袭厂。
  • finally方法的回調(diào)函數(shù)不接受任何參數(shù)
  • 沒有辦法知道,前面的 Promise 狀態(tài)到底是fulfilled還是rejected球匕。
  • finally方法里面的操作纹磺,與狀態(tài)無關(guān)的,不依賴于 Promise 的執(zhí)行結(jié)果
promise
.finally(() => {
  // 語句
});

// 等同于
promise
.then(
  result => {
    // 語句
    return result;
  },
  error => {
    // 語句
    throw error;
  }
);

9.Promise.all()

Promise.all()方法用于將多個 Promise 實例亮曹,包裝成一個新的 Promise 實例

  • Promise.all()方法接受一個數(shù)組作為參數(shù)橄杨,p1、p2乾忱、p3都是 Promise 實例
const p = Promise.all([p1, p2, p3]);

p的狀態(tài)由p1讥珍、p2、p3決定窄瘟,分成兩種情況衷佃。

(1)只有p1、p2蹄葱、p3的狀態(tài)都變成fulfilled氏义,p的狀態(tài)才會變成fulfilled,此時p1图云、p2惯悠、p3的返回值組成一個數(shù)組,傳遞給p的回調(diào)函數(shù)竣况。

(2)只要p1克婶、p2、p3之中有一個被rejected丹泉,p的狀態(tài)就變成rejected情萤,此時第一個被reject的實例的返回值,會傳遞給p的回調(diào)函數(shù)摹恨。

// 生成一個Promise對象的數(shù)組
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

promises是包含 6 個 Promise 實例的數(shù)組筋岛,只有這 6 個實例的狀態(tài)都變成fulfilled,或者其中有一個變?yōu)閞ejected晒哄,才會調(diào)用Promise.all方法后面的回調(diào)函數(shù)睁宰。

const databasePromise = connectDatabase();

const booksPromise = databasePromise
  .then(findAllBooks);

const userPromise = databasePromise
  .then(getCurrentUser);

Promise.all([
  booksPromise,
  userPromise
])
.then(([books, user]) => pickTopRecommendations(books, user));

上面代碼中,booksPromise和userPromise是兩個異步操作寝凌,只有等到它們的結(jié)果都返回了柒傻,才會觸發(fā)pickTopRecommendations這個回調(diào)函數(shù)。

注意:如果作為參數(shù)的 Promise 實例较木,自己定義了catch方法诅愚,那么它一旦被rejected,并不會觸發(fā)Promise.all()的catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('報錯了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 報錯了]

上面代碼中:
p1會resolved违孝,p2首先會rejected,但是p2有自己的catch方法泳赋,該方法返回的是一個新的 Promise 實例雌桑,p2指向的實際上是這個實例。該實例執(zhí)行完catch方法后祖今,也會變成resolved校坑,導(dǎo)致Promise.all()方法參數(shù)里面的兩個實例都會resolved,因此會調(diào)用then方法指定的回調(diào)函數(shù)千诬,而不會調(diào)用catch方法指定的回調(diào)函數(shù)耍目。

10.Promise.race()

Promise.race()方法同樣是將多個 Promise 實例,包裝成一個新的 Promise 實例

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

上面代碼中徐绑,只要p1邪驮、p2、p3之中有一個實例率先改變狀態(tài)傲茄,p的狀態(tài)就跟著改變毅访。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調(diào)函數(shù)盘榨。

11.Promise.allSettled()

確保所有操作都結(jié)束
Promise.allSettled()方法接受一組 Promise 實例作為參數(shù)喻粹,包裝成一個新的 Promise 實例。只有等到所有這些參數(shù)實例都返回結(jié)果草巡,不管是fulfilled還是rejected守呜,包裝實例才會結(jié)束

const promises = [
  fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises);
removeLoadingIndicator();

上面代碼對服務(wù)器發(fā)出三個請求,等到三個請求都結(jié)束山憨,不管請求成功還是失敗查乒,加載的滾動圖標就會消失。

12.Promise.any()

只要參數(shù)實例有一個變成fulfilled狀態(tài)萍歉,包裝實例就會變成fulfilled狀態(tài)侣颂;如果所有參數(shù)實例都變成rejected狀態(tài),包裝實例就會變成rejected狀態(tài)枪孩。

const promises = [
  fetch('/endpoint-a').then(() => 'a'),
  fetch('/endpoint-b').then(() => 'b'),
  fetch('/endpoint-c').then(() => 'c'),
];
try {
  const first = await Promise.any(promises);
  console.log(first);
} catch (error) {
  console.log(error);
}

上面代碼中憔晒,Promise.any()方法的參數(shù)數(shù)組包含三個 Promise 操作。其中只要有一個變成fulfilled蔑舞,Promise.any()返回的 Promise 對象就變成fulfilled拒担。如果所有三個操作都變成rejected,那么就會await命令就會拋出錯誤

13.Promise.resolve()

將現(xiàn)有對象轉(zhuǎn)為 Promise 對象

Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))

參數(shù):

  • 參數(shù)是一個 Promise 實例
    那么Promise.resolve將不做任何修改攻询、原封不動地返回這個實例从撼。
  • 參數(shù)是一個thenable對象
    thenable對象指的是具有then方法的對象,比如下面這個對象钧栖。
  • 參數(shù)不是具有then方法的對象低零,或根本就不是對象
  • 不帶有任何參數(shù)
let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

注意: 立即resolve()的 Promise 對象婆翔,是在本輪“事件循環(huán)”(event loop)的結(jié)束時執(zhí)行,而不是在下一輪“事件循環(huán)”的開始時掏婶。

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

setTimeout(fn, 0)在下一輪“事件循環(huán)”開始時執(zhí)行
Promise.resolve()在本輪“事件循環(huán)”結(jié)束時執(zhí)行
console.log('one')則是立即執(zhí)行啃奴,因此最先輸出

14.Promise.reject()

const p = Promise.reject('出錯了');
// 等同于
const p = new Promise((resolve, reject) => reject('出錯了'))

注意,Promise.reject()方法的參數(shù)雄妥,會原封不動地作為reject的理由最蕾,變成后續(xù)方法的參數(shù)。這一點與Promise.resolve方法不一致老厌。

const thenable = {
  then(resolve, reject) {
    reject('出錯了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})
// true

15.Promise.try()

事實上瘟则,Promise.try就是模擬try代碼塊,就像promise.catch模擬的是catch代碼塊枝秤。

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末醋拧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宿百,更是在濱河造成了極大的恐慌趁仙,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垦页,死亡現(xiàn)場離奇詭異雀费,居然都是意外死亡,警方通過查閱死者的電腦和手機痊焊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門盏袄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人薄啥,你說我怎么就攤上這事辕羽。” “怎么了垄惧?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵刁愿,是天一觀的道長。 經(jīng)常有香客問我到逊,道長铣口,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任觉壶,我火速辦了婚禮脑题,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铜靶。我一直安慰自己叔遂,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著已艰,像睡著了一般痊末。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哩掺,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天舌胶,我揣著相機與錄音,去河邊找鬼疮丛。 笑死,一個胖子當著我的面吹牛辆它,可吹牛的內(nèi)容都是我干的誊薄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼锰茉,長吁一口氣:“原來是場噩夢啊……” “哼呢蔫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起飒筑,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤片吊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后协屡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俏脊,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年肤晓,在試婚紗的時候發(fā)現(xiàn)自己被綠了爷贫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡补憾,死狀恐怖漫萄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盈匾,我是刑警寧澤腾务,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站削饵,受9級特大地震影響岩瘦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葵孤,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一担钮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尤仍,春花似錦箫津、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饼拍。三九已至,卻和暖如春田炭,著一層夾襖步出監(jiān)牢的瞬間师抄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工教硫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叨吮,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓瞬矩,卻偏偏與公主長得像茶鉴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子景用,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

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

  • Promise 是異步編程的一種解決方案涵叮,比傳統(tǒng)的解決方案 —— 回調(diào)函數(shù)和事件 —— 更合理且強大 Promis...
    了凡和纖風(fēng)閱讀 520評論 0 1
  • async 函數(shù) 含義 ES2017 標準引入了 async 函數(shù),使得異步操作變得更加方便伞插。 async函數(shù)對 ...
    Xyaleo閱讀 1,088評論 0 4
  • 1. Promise 的含義 所謂Promise割粮,簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個...
    ROBIN2015閱讀 484評論 0 0
  • 含義 Promise是異步編程的一種解決方案媚污,用于一個異步操作的最終完成(或失敗)及其結(jié)果值的表示舀瓢,比傳統(tǒng)的回調(diào)函...
    nimw閱讀 26,833評論 0 4
  • 獨自回想 那雙明亮的眼睛, 像窗杠步, 連接無窮的天空氢伟, 讓我偷偷收藏; 夢里看到 那雙清澈的眼睛幽歼, 像溪朵锣, 流向未知...
    筆拓的簡書閱讀 392評論 2 4