ECMAScript6基礎(chǔ)學(xué)習(xí)教程(八)Promise

JavaScript被設(shè)計(jì)為單線程(webWoker可以處理多線程)虑鼎,利用事件輪詢機(jī)制辱匿,可以模擬出多線程效果,也就是異步操作炫彩,而回調(diào)函數(shù)callback是事件輪詢調(diào)用的目標(biāo)方法匾七。

但是,通過(guò)回調(diào)函數(shù)處理異步事件有很多不確定性江兢,并且容易陷入“回調(diào)地獄”-嵌套太深昨忆。于是,Promise概念被提出杉允,并且很多JavaScript框架(比如JQuery)支持的異步API都基于Promise理念構(gòu)建的邑贴。

1.什么是Promise?

Promise是一個(gè)對(duì)象叔磷,用來(lái)傳遞異步操作的信息拢驾,它代表了某個(gè)未來(lái)時(shí)刻才知道結(jié)果的事件,并且這個(gè)事件提供統(tǒng)一API接口世澜。

2. Promise對(duì)象

Promise原型對(duì)象提供的主要方法有:

//添加狀態(tài)改變時(shí)的回調(diào)函數(shù)
Promise.prototype.then(resolvedFunc, rejectedFunc) 
//響應(yīng)rejected狀態(tài)的promise(如果前面有錯(cuò)誤拋出独旷,會(huì)產(chǎn)生一個(gè)rejected狀態(tài)的promise)
//相當(dāng)于promise.then(null, rejectedFunc)
Promise.prototype.catch(rejectedFunc) 

參考一個(gè)標(biāo)準(zhǔn)的Promise實(shí)例:

var promise = new Promise(function(resolve, reject){
  // 你的代碼---pending狀態(tài)
  if (isSuccessful) {
    resolve(value); // 成功
  }
  else {
    reject(error); // 失敗
  }
// 這里的代碼永遠(yuǎn)不會(huì)被運(yùn)行
});

promise
.then(
  function(value){//resolved時(shí)調(diào)用}, 
  function(error){// rejected時(shí)調(diào)用})
.catch(function(error){//有錯(cuò)誤拋出時(shí)調(diào)用});

promise對(duì)象有如下特點(diǎn):

  1. 可以利用promise對(duì)象創(chuàng)建一個(gè)異步操作。
  2. 有三種狀態(tài):pending, resolved和rejected寥裂。異步代碼運(yùn)行時(shí)為pending嵌洼,運(yùn)行后的結(jié)果只會(huì)是兩種:成功-resolved,或者失敗-rejected封恰。狀態(tài)變化是單行流動(dòng)麻养,不可逆轉(zhuǎn)。
  3. 在一個(gè)promise里诺舔,resolve或者reject方法只會(huì)被調(diào)用一次鳖昌。
  4. resolve()/reject()可以利用參數(shù)傳遞數(shù)據(jù)备畦,但是,只支持傳遞第一個(gè)參數(shù)许昨。也就是說(shuō)懂盐,promise決議只能傳遞單個(gè)值/對(duì)象。因此糕档,實(shí)際應(yīng)用中莉恼,需要將多個(gè)值封裝在一個(gè)對(duì)象中傳遞
  5. then()和catch()函數(shù)都會(huì)默認(rèn)返回一個(gè)promise對(duì)象速那。
  6. 如果沒(méi)有給then()傳遞函數(shù)作為完成處理函數(shù)參數(shù)俐银,還是會(huì)有替代的默認(rèn)處理函數(shù),并且端仰,該默認(rèn)函數(shù)會(huì)把接受到的值傳遞給下一個(gè)promise對(duì)象捶惜。
getPromise(40, true).
    then(null,null).then(function (value) {
    console.log("resolved:"+value);
});
// 打印:resolved:40
// 可見(jiàn)荔烧,如果不設(shè)置then的處理函數(shù)參數(shù)吱七,resolved值40一直會(huì)被傳遞下去。

3. 一個(gè)Promise實(shí)例

下面是一個(gè)Promise例子茴晋,參考注釋陪捷。
創(chuàng)建promise的工廠方法:

var getPromise = function (val, isSuccessful) {
    var promise = new Promise(function (resolve, reject) {
        setTimeout(function () {
            if (isSuccessful) {
                // 決議成功,回調(diào)then()的第一個(gè)函數(shù)參數(shù)
                resolve(val); 
            }
            else {
                // 決議失敗诺擅,回調(diào)then()的第二個(gè)函數(shù)參數(shù)
                reject(new Error("oh, error!")); 
            }
        }, 0);
    });
    return promise;
};

第一次測(cè)試(連續(xù)調(diào)用兩次promise):

getPromise(30, true).then((value) => {
    console.log("the first resolved status: " + value);
    // 返回一個(gè)promise對(duì)象市袖,該promise決議結(jié)果會(huì)決定下一個(gè)then()函數(shù)應(yīng)該調(diào)用哪個(gè)回調(diào)函數(shù)
    // 如果不顯性返回promise對(duì)象,ES6會(huì)默認(rèn)創(chuàng)建一個(gè)空值promise對(duì)象最為返回值
    return getPromise(20, true);
}, (error) => {
    console.log("the second rejected status: " + error);
}).then((value) => {
    console.log("the second resolved status: " + value);
    // 一個(gè)rejected狀態(tài)的promise對(duì)象被返回
    //由于后續(xù)沒(méi)有then()烁涌,因此catch函數(shù)捕獲錯(cuò)誤狀態(tài)
    throw new Error('create a error!');
}, (error) => {
    console.log("the second rejected status: " + error);
}).catch((error) => {
    console.log("Catch: " + error);
});

//運(yùn)行結(jié)果:
the first resolved status: 30
the second resolved status: 20
Catch: Error: create a error!

第二次測(cè)試(多加一個(gè)then調(diào)用):

getPromise(30, true).then((value) => {
    console.log("the first resolved status: " + value);
    return getPromise(20, true);
}, (error) => {
    console.log("the second rejected status: " + error);
}).then((value) => {
    console.log("the second resolved status: " + value);
    // 一個(gè)rejected狀態(tài)的promise對(duì)象被返回
    //由于后續(xù)有then()苍碟,因此then函數(shù)的第二個(gè)回調(diào)函數(shù)被運(yùn)行
    throw new Error('create a error!');
}, (error) => {
    console.log("the second rejected status: " + error);
}).then((value) => {
    console.log("the third resolved status: " + value);
}, (error) => {
    console.log("the third rejected status: " + error);
}).catch((error) => {
    console.log("Catch: " + error);
});

// 運(yùn)行結(jié)果:
the first resolved status: 30
the second resolved status: 20
the third rejected status: Error: create the first error!

第三次測(cè)試(修改getPromise函數(shù)):

var getPromise = function (val, isSuccessful) {
    var promise = new Promise(function (resolve, reject) {
         if (isSuccessful) {
                resolve(val);
                //resolve之后拋出錯(cuò)誤,是不會(huì)被捕獲的
                throw new Error('error, error, error!');
            }
            else {
                reject(new Error("oh, error!"));
            }
    });
    return promise;
};
// 測(cè)試1和測(cè)試2的運(yùn)行結(jié)果不會(huì)改變

從上面的例子可以看到撮执,可以用同步書寫方式連續(xù)調(diào)用多個(gè)異步請(qǐng)求微峰。并且,Promise還提供了靜態(tài)函數(shù)幫助解決更復(fù)雜的異步編程場(chǎng)景抒钱。

4. Promise靜態(tài)方法

Promise提供的靜態(tài)方法有:

Promise.all([promise1, promise2 [,promiseN]])
Promise.race([promise1, promise2 [,promiseN])
Promise.resolve()
Promise.reject()
(1) Promise.all()

將多個(gè)promise實(shí)例包裝成一個(gè)新的promise對(duì)象蜓肆,只有多個(gè)promise的狀態(tài)都為resolved允瞧,Promise.all()的狀態(tài)才會(huì)變?yōu)閞esolved备韧。
繼續(xù)上面的例子志群,測(cè)試如下:

Promise.all([
    getPromise(20, true),
    getPromise(30, true), 
    getPromise(40, true)])
    .then(function (value) {
        console.log(value);
    });
// 輸出為:[ 20, 30, 40 ]

每個(gè)Promise實(shí)例的resolved值都會(huì)暫存在一個(gè)數(shù)組里桨醋,最后,該數(shù)組被傳遞到Promise.all()的resolved回調(diào)函數(shù)崭庸。

(2) Promise.race()

將多個(gè)promise實(shí)例包裝成一個(gè)新的promise對(duì)象属划,只有第一個(gè)promise狀態(tài)為resolved時(shí)涧至,Promise.race()的狀態(tài)才變?yōu)閞esolved诅蝶。

并且退个,第一個(gè)promise的值會(huì)傳遞給Promise.race()募壕。

基于上面例子繼續(xù)測(cè)試:

Promise.race([
    getPromise(20, true),
    getPromise(30, false),
    getPromise(40, false)])
    .then(function (value) {
        console.log(value);
    }, function (error) {
        console.log(error);
    });
//輸出為: 20

Promise.race([
    getPromise(20, false),
    getPromise(30, true),
    getPromise(40, false)])
    .then(function (value) {
        console.log(value);
    }, function (error) {
        console.log(error);
    });
// 輸出為: [Error: oh, error!]
(3) Promise.resolve()

該方法會(huì)返回一個(gè)Promise對(duì)象,情況分為兩種:

  • 如果目標(biāo)對(duì)象不是Promise對(duì)象语盈,該方法會(huì)創(chuàng)建一個(gè)Promise對(duì)象
  • 如果目標(biāo)對(duì)象本身就是Promise對(duì)象舱馅,該方法會(huì)將這個(gè)Promise對(duì)象直接返回
// p2和p1行為完全一樣
var p1 = new Promise(function(resolve, reject){
  resolve(40);
});
var p2 = Promise.resolve(40);
// 向Promise.resolve()傳遞一個(gè)Promise對(duì)象,則直接返回這個(gè)對(duì)象
var p3 = Promise.resolve(p2);
console.log(p2===p3); // true
(4) Promise.reject()

返回一個(gè)新的Promise實(shí)例黎烈,狀態(tài)為rejected:

var p = new Promise(function(resolve, reject){
  reject("error");
}); 

//可以用 Promise.reject()快速創(chuàng)建promise對(duì)象习柠,狀態(tài)為rejected
var p = Promise.reject("error");
p.then(null, function(error) {
// 回調(diào)函數(shù)被調(diào)用
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市照棋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌武翎,老刑警劉巖烈炭,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宝恶,居然都是意外死亡符隙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門垫毙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)霹疫,“玉大人,你說(shuō)我怎么就攤上這事综芥±鲂” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵膀藐,是天一觀的道長(zhǎng)屠阻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)额各,這世上最難降的妖魔是什么国觉? 我笑而不...
    開(kāi)封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮虾啦,結(jié)果婚禮上麻诀,老公的妹妹穿的比我還像新娘。我一直安慰自己傲醉,他們只是感情好蝇闭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著需频,像睡著了一般丁眼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昭殉,一...
    開(kāi)封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天苞七,我揣著相機(jī)與錄音藐守,去河邊找鬼。 笑死蹂风,一個(gè)胖子當(dāng)著我的面吹牛卢厂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惠啄,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼慎恒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了撵渡?” 一聲冷哼從身側(cè)響起融柬,我...
    開(kāi)封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎趋距,沒(méi)想到半個(gè)月后粒氧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡节腐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年外盯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翼雀。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饱苟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狼渊,到底是詐尸還是另有隱情箱熬,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布囤锉,位于F島的核電站坦弟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏官地。R本人自食惡果不足惜酿傍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驱入。 院中可真熱鬧赤炒,春花似錦、人聲如沸亏较。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雪情。三九已至遵岩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尘执。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工舍哄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人誊锭。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓表悬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親丧靡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蟆沫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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

  • > 簡(jiǎn)述: ## 什么是Promise? -Promise是用來(lái)處理異步的; -Promise就是承諾,對(duì)未來(lái)的承...
    風(fēng)雪中的兔子閱讀 380評(píng)論 0 0
  • Promise含義 Promise是異步編程的一種解決方案温治,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更強(qiáng)大饭庞。所謂Pr...
    oWSQo閱讀 1,083評(píng)論 0 4
  • Promise的含義 Promise是異步編程的一種解決方案,ES6將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn)罐盔。所謂的Promise就是一...
    橙色流年閱讀 426評(píng)論 0 1
  • 14.1 含義 Promise保存著一個(gè)異步操作的結(jié)果 特點(diǎn) 對(duì)象的狀態(tài)不受外界影響 一旦狀態(tài)改變但绕,就不會(huì)再變,任...
    WiFi_Uncle閱讀 510評(píng)論 0 1
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器惶看,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō)六孵,Pr...
    雨飛飛雨閱讀 3,352評(píng)論 0 19