對Promise機制的理解

Promise是一套解決編程中異步操作問題的方案。所謂Promise對象,其實就像一個容器,包裹著一個未來才會發(fā)生(或結(jié)束)的事件的結(jié)果榴芳。比如發(fā)請求嗡靡,請求發(fā)出去之后要等一段時間之后才能收到結(jié)果(即使這個時間很短,但總不是立刻就能收到響應(yīng)窟感;為方便理解讨彼,你也可以夸張一點想象,比如請求發(fā)出之后要幾天才能得到響應(yīng))柿祈。

Promise對象的特點

1.對象的狀態(tài)不受外界影響哈误,只取決于異步操作的結(jié)果。Promise的狀態(tài)有三種:pending(進行中)谍夭、fulfilled(已成功,后面用resolved代替)和rejected(已失敽┠肌)紧索。Promise的狀態(tài)的改變?nèi)Q于異步操作的結(jié)果,如果異步操作是成功的菜谣,那么狀態(tài)由pending變成fulfilled珠漂,否則由pending變成rejected.
2.一旦狀態(tài)改變,就不會再變尾膊,任何時候都可以得到這個結(jié)果媳危。如果異步操作已經(jīng)成功了,那么它的狀態(tài)就變成了fulfilled,你任何時候傳入回調(diào)函數(shù)冈敛,它都只會執(zhí)行“成功的回調(diào)函數(shù)”待笑。
3.Promise對象一旦新建就會立即執(zhí)行。

缺點:如果不設(shè)置回調(diào)函數(shù)抓谴,promise拋出錯誤信息不會傳到外部暮蹂,只是內(nèi)部自己知道。

resolve()和reject()函數(shù)

//創(chuàng)建一個Promise實例,這里即promise
const promise= new Promise(function(resolve,reject){
if(/*異步操作成功*/)
  resolve() //調(diào)用resolve癌压,將promise的狀態(tài)改為fulfilled仰泻,后面會根據(jù)這個狀態(tài)去調(diào)用相應(yīng)的回調(diào)函數(shù)
})else{
/*異步操作失敗*/
  reject() //調(diào)用reject,將promise的狀態(tài)改為rejected滩届,后面會根據(jù)這個狀態(tài)去調(diào)用相應(yīng)的回調(diào)函數(shù)
}

文檔中有一段話很重要集侯,可以幫助你很好的理解resolve和reject函數(shù)的作用:
resolve函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved)帜消,在異步操作成功時調(diào)用棠枉,并將異步操作的結(jié)果,作為參數(shù)傳遞出去泡挺;reject函數(shù)的作用是术健,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時調(diào)用粘衬,并將異步操作報出的錯誤荞估,作為參數(shù)傳遞出去咳促。

從這段話我們可以總結(jié)出resolve和reject函數(shù)兩個重要的作用
1.改變狀態(tài)
2.將異步操作的結(jié)果傳出去。異步操作的結(jié)果會作為resolve和reject的參數(shù)傳遞出去勘伺。

promise實例的then()方法

Promise實例生成后跪腹,有一個then()方法,這個方法接受2個參數(shù)飞醉,分別是promise對象狀態(tài)是resolved時調(diào)用的函數(shù)冲茸,和promise對象狀態(tài)是rejected時調(diào)用的函數(shù)。如果調(diào)用resolve函數(shù)和reject函數(shù)時帶有參數(shù)缅帘,那么它們的參數(shù)會被傳遞給回調(diào)函數(shù)轴术。
一般來說,調(diào)用resolve或reject以后钦无,Promise 的使命就完成了逗栽,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面失暂。所以彼宠,最好在resolve()前面加上return語句,這樣就不會有意外弟塞。

幾個例子

  • promise創(chuàng)建后立即執(zhí)行
let promise = new Promise(function(resolve, reject) {
  console.log('Promise');  //創(chuàng)建后立即執(zhí)行凭峡,所以打印出‘Promise’
  resolve();
});

promise.then(function() { //promise對象的回調(diào),會被推入到異步進程里决记,要等到所有同步腳本執(zhí)行完才會執(zhí)行
  console.log('resolved.');
});

console.log('Hi!'); //在創(chuàng)建promise對象之后的同步腳本摧冀,打印出‘Hi’

// Promise
// Hi!
// resolved

Promise 新建后立即執(zhí)行,所以首先輸出的是Promise系宫。然后按价,then方法指定的回調(diào)函數(shù),將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會執(zhí)行笙瑟,所以resolved最后輸出楼镐。

  • 用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);
});
  • resolve函數(shù)的參數(shù)可以是另外一個promise對象
const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

以上,p2 的reslove()方法將p1作為參數(shù)往枷。這時候框产,p2的狀態(tài)變成了由p1決定,如果p1的狀態(tài)是pending错洁,那么p2的回調(diào)函數(shù)就會等待p1的狀態(tài)改變秉宿;如果p1的狀態(tài)已經(jīng)是resolved或者rejected,那么p2的回調(diào)函數(shù)將會立刻執(zhí)行屯碴。
上面代碼中描睦,p1是一個 Promise,3 秒之后變?yōu)閞ejected导而。p2的狀態(tài)在 1 秒之后改變忱叭,resolve方法返回的是p1隔崎。由于p2返回的是另一個 Promise,導(dǎo)致p2自己的狀態(tài)無效了韵丑,由p1的狀態(tài)決定p2的狀態(tài)爵卒。所以,后面的then語句都變成針對后者(p1)撵彻。又過了 2 秒钓株,p1變?yōu)閞ejected,導(dǎo)致觸發(fā)catch方法指定的回調(diào)函數(shù)陌僵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末轴合,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子碗短,更是在濱河造成了極大的恐慌受葛,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豪椿,死亡現(xiàn)場離奇詭異奔坟,居然都是意外死亡携栋,警方通過查閱死者的電腦和手機搭盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來婉支,“玉大人鸯隅,你說我怎么就攤上這事∠蛲冢” “怎么了蝌以?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長何之。 經(jīng)常有香客問我跟畅,道長,這世上最難降的妖魔是什么溶推? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任徊件,我火速辦了婚禮,結(jié)果婚禮上蒜危,老公的妹妹穿的比我還像新娘虱痕。我一直安慰自己,他們只是感情好辐赞,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布部翘。 她就那樣靜靜地躺著,像睡著了一般响委。 火紅的嫁衣襯著肌膚如雪新思。 梳的紋絲不亂的頭發(fā)上窖梁,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音表牢,去河邊找鬼窄绒。 笑死,一個胖子當(dāng)著我的面吹牛崔兴,可吹牛的內(nèi)容都是我干的彰导。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼敲茄,長吁一口氣:“原來是場噩夢啊……” “哼位谋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起堰燎,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤掏父,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秆剪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赊淑,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年仅讽,在試婚紗的時候發(fā)現(xiàn)自己被綠了陶缺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡洁灵,死狀恐怖饱岸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徽千,我是刑警寧澤苫费,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站双抽,受9級特大地震影響百框,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜牍汹,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一铐维、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柑贞,春花似錦方椎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春闸拿,著一層夾襖步出監(jiān)牢的瞬間空盼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工新荤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留揽趾,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓苛骨,卻偏偏與公主長得像篱瞎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子痒芝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

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