promise 實(shí)踐

Promise 對象用于一個異步操作的最終完成(或失敗)及其結(jié)果值的表示印蔬。簡單點(diǎn)說勋桶,它就是用于處理異步操作的,異步處理成功了就執(zhí)行成功的操作侥猬,異步處理失敗了就捕獲錯誤或者停止后續(xù)操作例驹。

它的一般表示形式為:

    /* executor */
    function(resolve, reject) {
        if (/* success */) {
            // ...執(zhí)行代碼
            resolve();
        } else { /* fail */
            // ...執(zhí)行代碼
            reject();
        }
    }
);

其中,Promise中的參數(shù)executor是一個執(zhí)行器函數(shù)退唠,它有兩個參數(shù)resolve和reject鹃锈。它內(nèi)部通常有一些異步操作,如果異步操作成功瞧预,則可以調(diào)用resolve()來將該實(shí)例的狀態(tài)置為fulfilled屎债,即已完成的,如果一旦失敗垢油,可以調(diào)用reject()來將該實(shí)例的狀態(tài)置為rejected盆驹,即失敗的。

我們可以把Promise對象看成是一條工廠的流水線滩愁,對于流水線來說躯喇,從它的工作職能上看,它只有三種狀態(tài)惊楼,一個是初始狀態(tài)(剛開機(jī)的時候)玖瘸,一個是加工產(chǎn)品成功,一個是加工產(chǎn)品失斕戳(出現(xiàn)了某些故障)雅倒。同樣對于Promise對象來說,它也有三種狀態(tài):

pending
初始狀態(tài),也稱為未定狀態(tài)弧可,就是初始化Promise時蔑匣,調(diào)用executor執(zhí)行器函數(shù)后的狀態(tài)。
fulfilled
完成狀態(tài)棕诵,意味著異步操作成功裁良。
rejected
失敗狀態(tài),意味著異步操作失敗校套。
它只有兩種狀態(tài)可以轉(zhuǎn)化价脾,即

操作成功
pending -> fulfilled
操作失敗
pending -> rejected
并且這個狀態(tài)轉(zhuǎn)化是單向的,不可逆轉(zhuǎn)笛匙,已經(jīng)確定的狀態(tài)(fulfilled/rejected)無法轉(zhuǎn)回初始狀態(tài)(pending)侨把。

方法

Promise.prototype.then()

Promise對象含有then方法犀变,then()調(diào)用后返回一個Promise對象,意味著實(shí)例化后的Promise對象可以進(jìn)行鏈?zhǔn)秸{(diào)用秋柄,而且這個then()方法可以接收兩個函數(shù)获枝,一個是處理成功后的函數(shù),一個是處理錯誤結(jié)果的函數(shù)骇笔。

如下:

var promise1 = new Promise(function(resolve, reject) {
  // 2秒后置為接收狀態(tài)
  setTimeout(function() {
    resolve('success');
  }, 2000);
});

promise1.then(function(data) {
  console.log(data); // success
}, function(err) {
  console.log(err); // 不執(zhí)行
}).then(function(data) {
  // 上一步的then()方法沒有返回值
  console.log('鏈?zhǔn)秸{(diào)用:' + data); // 鏈?zhǔn)秸{(diào)用:undefined 
}).then(function(data) {
  // ....
});

在這里我們主要關(guān)注promise1.then()方法調(diào)用后返回的Promise對象的狀態(tài)省店,是pending還是fulfilled,或者是rejected?

返回的這個Promise對象的狀態(tài)主要是根據(jù)promise1.then()方法返回的值笨触,大致分為以下幾種情況:

如果then()方法中返回了一個參數(shù)值懦傍,那么返回的Promise將會變成接收狀態(tài)。
如果then()方法中拋出了一個異常旭旭,那么返回的Promise將會變成拒絕狀態(tài)谎脯。
如果then()方法調(diào)用resolve()方法,那么返回的Promise將會變成接收狀態(tài)持寄。
如果then()方法調(diào)用reject()方法源梭,那么返回的Promise將會變成拒絕狀態(tài)。
如果then()方法返回了一個未知狀態(tài)(pending)的Promise新實(shí)例稍味,那么返回的新Promise就是未知狀態(tài)废麻。
如果then()方法沒有明確指定的resolve(data)/reject(data)/return data時,那么返回的新Promise就是接收狀態(tài)模庐,可以一層一層地往下傳遞烛愧。
轉(zhuǎn)換實(shí)例如下:

var promise2 = new Promise(function(resolve, reject) {
  // 2秒后置為接收狀態(tài)
  setTimeout(function() {
    resolve('success');
  }, 2000);
});

promise2
  .then(function(data) {
    // 上一個then()調(diào)用了resolve,置為fulfilled態(tài)
    console.log('第一個then');
    console.log(data);
    return '2';
  })
  .then(function(data) {
    // 此時這里的狀態(tài)也是fulfilled, 因?yàn)樯弦徊椒祷亓?
    console.log('第二個then');
    console.log(data);  // 2

    return new Promise(function(resolve, reject) {
      reject('把狀態(tài)置為rejected error'); // 返回一個rejected的Promise實(shí)例
    });
  }, function(err) {
    // error
  })
  .then(function(data) {
    /* 這里不運(yùn)行 */
    console.log('第三個then');
    console.log(data);
    // ....
  }, function(err) {
    // error回調(diào)
    // 此時這里的狀態(tài)也是fulfilled, 因?yàn)樯弦徊绞褂昧藃eject()來返回值
    console.log('出錯:' + err); // 出錯:把狀態(tài)置為rejected error
  })
  .then(function(data) {
    // 沒有明確指定返回值掂碱,默認(rèn)返回fulfilled
    console.log('這里是fulfilled態(tài)');
});
Promise.prototype.catch()
catch()方法和then()方法一樣怜姿,都會返回一個新的Promise對象,它主要用于捕獲異步操作時出現(xiàn)的異常疼燥。因此沧卢,我們通常省略then()方法的第二個參數(shù),把錯誤處理控制權(quán)轉(zhuǎn)交給其后面的catch()函數(shù)醉者,如下:

var promise3 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('reject');
  }, 2000);
});

promise3.then(function(data) {
  console.log('這里是fulfilled狀態(tài)'); // 這里不會觸發(fā)
  // ...
}).catch(function(err) {
  // 最后的catch()方法可以捕獲在這一條Promise鏈上的異常
  console.log('出錯:' + err); // 出錯:reject
});

Promise.all()

Promise.all()接收一個參數(shù)但狭,它必須是可以迭代的,比如數(shù)組撬即。

它通常用來處理一些并發(fā)的異步操作立磁,即它們的結(jié)果互不干擾,但是又需要異步執(zhí)行剥槐。它最終只有兩種狀態(tài):成功或者失敗唱歧。

它的狀態(tài)受參數(shù)內(nèi)各個值的狀態(tài)影響,即里面狀態(tài)全部為fulfilled時粒竖,它才會變成fulfilled颅崩,否則變成rejected绍刮。

成功調(diào)用后返回一個數(shù)組,數(shù)組的值是有序的挨摸,即按照傳入?yún)?shù)的數(shù)組的值操作后返回的結(jié)果。如下:

// 置為fulfilled狀態(tài)的情況
var arr = [1, 2, 3];
var promises = arr.map(function(e) {
  return new Promise(function(resolve, reject) {
    resolve(e * 5);
  });
});

Promise.all(promises).then(function(data) {
    // 有序輸出
  console.log(data); // [5, 10, 15]
  console.log(arr); // [1, 2, 3]
});
// 置為rejected狀態(tài)的情況
var arr = [1, 2, 3];
var promises2 = arr.map(function(e) {
  return new Promise(function(resolve, reject) {
    if (e === 3) {
      reject('rejected');
    }
    resolve(e * 5);
  });
});

Promise.all(promises2).then(function(data) {
  // 這里不會執(zhí)行
  console.log(data);
  console.log(arr);
}).catch(function(err) {
  console.log(err); // rejected
});

Promise.race()

Promise.race()和Promise.all()類似岁歉,都接收一個可以迭代的參數(shù)得运,但是不同之處是Promise.race()的狀態(tài)變化不是全部受參數(shù)內(nèi)的狀態(tài)影響,一旦參數(shù)內(nèi)有一個值的狀態(tài)發(fā)生的改變锅移,那么該P(yáng)romise的狀態(tài)就是改變的狀態(tài)熔掺。就跟race單詞的字面意思一樣,誰跑的快誰贏非剃。如下:

var p1 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 300, 'p1 doned');
});

var p2 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 50, 'p2 doned');
});

var p3 = new Promise(function(resolve, reject) {
  setTimeout(reject, 100, 'p3 rejected');
});

Promise.race([p1, p2, p3]).then(function(data) {
  // 顯然p2更快置逻,所以狀態(tài)變成了fulfilled
  // 如果p3更快,那么狀態(tài)就會變成rejected
  console.log(data); // p2 doned
}).catch(function(err) {
  console.log(err); // 不執(zhí)行
});

Promise.resolve()

Promise.resolve()接受一個參數(shù)值备绽,可以是普通的值券坞,具有then()方法的對象和Promise實(shí)例。正常情況下肺素,它返回一個Promise對象恨锚,狀態(tài)為fulfilled。但是倍靡,當(dāng)解析時發(fā)生錯誤時猴伶,返回的Promise對象將會置為rejected態(tài)。如下:

// 參數(shù)為普通值
var p4 = Promise.resolve(5);
p4.then(function(data) {
  console.log(data); // 5
});


// 參數(shù)為含有then()方法的對象
var obj = {
  then: function() {
    console.log('obj 里面的then()方法');
  }
};

var p5 = Promise.resolve(obj);
p5.then(function(data) {
  // 這里的值時obj方法里面返回的值
  console.log(data); // obj 里面的then()方法
});


// 參數(shù)為Promise實(shí)例
var p6 = Promise.resolve(7);
var p7 = Promise.resolve(p6);

p7.then(function(data) {
  // 這里的值時Promise實(shí)例返回的值
  console.log(data); // 7
});

// 參數(shù)為Promise實(shí)例,但參數(shù)是rejected態(tài)
var p8 = Promise.reject(8);
var p9 = Promise.resolve(p8);

p9.then(function(data) {
  // 這里的值時Promise實(shí)例返回的值
  console.log('fulfilled:'+ data); // 不執(zhí)行
}).catch(function(err) {
  console.log('rejected:' + err); // rejected: 8
});
Promise.reject()
Promise.reject()和Promise.resolve()正好相反塌西,它接收一個參數(shù)值reason他挎,即發(fā)生異常的原因。此時返回的Promise對象將會置為rejected態(tài)捡需。如下:

var p10 = Promise.reject('手動拒絕');
p10.then(function(data) {
  console.log(data); // 這里不會執(zhí)行办桨,因?yàn)槭莚ejected態(tài)
}).catch(function(err) {
  console.log(err); // 手動拒絕
}).then(function(data) {
 // 不受上一級影響
  console.log('狀態(tài):fulfilled'); // 狀態(tài):fulfilled
});

總之,除非Promise.then()方法內(nèi)部拋出異称苤遥或者是明確置為rejected態(tài)崔挖,否則它返回的Promise的狀態(tài)都是fulfilled態(tài),即完成態(tài)庵寞,并且它的狀態(tài)不受它的上一級的狀態(tài)的影響

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狸相,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捐川,更是在濱河造成了極大的恐慌脓鹃,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件古沥,死亡現(xiàn)場離奇詭異瘸右,居然都是意外死亡娇跟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門太颤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苞俘,“玉大人,你說我怎么就攤上這事龄章〕砸ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵做裙,是天一觀的道長岗憋。 經(jīng)常有香客問我,道長锚贱,這世上最難降的妖魔是什么仔戈? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拧廊,結(jié)果婚禮上监徘,老公的妹妹穿的比我還像新娘。我一直安慰自己吧碾,他們只是感情好耐量,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滤港,像睡著了一般廊蜒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上溅漾,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天山叮,我揣著相機(jī)與錄音,去河邊找鬼添履。 笑死屁倔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的暮胧。 我是一名探鬼主播锐借,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼往衷!你這毒婦竟也來了钞翔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤席舍,失蹤者是張志新(化名)和其女友劉穎布轿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汰扭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年稠肘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萝毛。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡项阴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笆包,到底是詐尸還是另有隱情鲁冯,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布色查,位于F島的核電站,受9級特大地震影響撞芍,放射性物質(zhì)發(fā)生泄漏秧了。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一序无、第九天 我趴在偏房一處隱蔽的房頂上張望验毡。 院中可真熱鬧,春花似錦帝嗡、人聲如沸晶通。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狮辽。三九已至,卻和暖如春巢寡,著一層夾襖步出監(jiān)牢的瞬間喉脖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工抑月, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留树叽,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓谦絮,卻偏偏與公主長得像题诵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子层皱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

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