對Promise機制的理解

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

Promise對象的特點

1.對象的狀態(tài)不受外界影響,只取決于異步操作的結(jié)果。Promise的狀態(tài)有三種:pending(進行中)、fulfilled(已成功,后面用resolved代替)和rejected(已失?。romise的狀態(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í)行。

缺點:如果不設置回調(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)用相應的回調(diào)函數(shù)
})else{
/*異步操作失敗*/
  reject() //調(diào)用reject,將promise的狀態(tài)改為rejected,后面會根據(jù)這個狀態(tài)去調(diào)用相應的回調(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 的使命就完成了,后繼操作應該放到then方法里面,而不應該直接寫在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ù),將在當前腳本所有同步任務執(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,導致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)。所以,后面的then語句都變成針對后者(p1)。又過了 2 秒,p1變?yōu)閞ejected,導致觸發(fā)catch方法指定的回調(diào)函數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容