Promise的基本應用

weixin_33670713發表於2018-09-18

Promise 物件是 JavaScript 的非同步操作解決方案,為非同步操作提供統一介面。
它起到代理作用(proxy),充當非同步操作與回撥函式之間的中介,使得非同步操作具備同步操作的介面。
Promise 的設計思想是,所有非同步任務都返回一個 Promise 例項。
Promise 例項有一個then方法,用來指定下一步的回撥函式。


Promise物件的狀態

Promise物件有三個狀態
  • pending 進行中
  • fulfilled 成功
  • rejected 失敗
特點
  • 物件的狀態不受外界影響
    只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
  • 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。

Promise 物件狀態改變只有兩種可能:
pending → fulfilled
pending → rejected
一旦改變了,狀態就不會發生變化了,這時候稱為 resolved(已定型)


Promise 建構函式

Promise建構函式接受一個函式作為引數,該函式的兩個引數分別是resolve和reject。它們是兩個函式,由 JavaScript 引擎提供,不用自己部署。

生成一個promise例項:

let promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 非同步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve 函式在非同步操作成功時呼叫,並將非同步操作的結果作為引數傳遞出去;
reject 函式在非同步操作失敗時呼叫,並將非同步操作報出的錯誤,作為引數傳遞出去。

Promise例項生成以後,可以用then方法分別指定resolved狀態和rejected狀態的回撥函式。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

鏈式呼叫

$.ajax(/*code*/).then(成功函式1 , 失敗函式1   )
                .then(成功函式2,  失敗函式1 )

思考:上面程式碼中的成功函式2在什麼情況下會被呼叫?
答案是: 只要前面成功函式/失敗函式沒有報錯,都會呼叫 成功函式2。

  • 前面函式 沒有報錯 的情況:
// 先生成一個 promise 物件
var promise = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1)
  },2000)  
})

promise
   .then((res)=>{
  console.log('成功函式1執行了')   
})
   .then(()=>{
  console.log('成功函式2執行了')
},(err)=>{
   console.log('失敗函式2呼叫了')
}) //  依次列印出 成功函式1執行了   成功函式2執行了
var promise = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(1)
  },2000)  
})

promise
// .catch方法是.then(null, rejection)的別名
   .catch((err)=>{
  console.log('失敗函式1執行了') 
})
   .then(()=>{
  console.log('成功函式2執行了')
},(err)=>{
   console.log('失敗函式2執行了')
}) //   失敗函式1執行了    成功函式2執行了

只要前面的回撥函式沒有報錯,都會呼叫 成功函式2

  • 前面成功函式報錯時,呼叫失敗函式2
var promise = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1)
  },2000)  
})

promise
   .then((res)=>{
  throw new Error('成功函式1 報錯了') 
})
   .then(()=>{
  console.log('成功函式2執行了')
},(err)=>{
   console.log('失敗函式2呼叫了')
}) // 失敗函式2呼叫了

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回撥函式。

Promise 物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止。
所以可以不在then 裡定義reject的回撥函式,而用catch代替(推薦)

// 一個不太嚴謹的例子,用隨機數是否大於0.5 來模擬成功和失敗.....
let promise = new Promise(function(resolve,reject) { 
  let rand = Math.random();
  let success = rand>0.5 ;
  console.log(success);
  if(success) {
    resolve(rand)
  } else {
    reject(rand)
  }
});

promise
  .then(res=> console.log(res) )
  .catch(error => console.log(error))

另外,Promise 內部的錯誤不會影響到 Promise 外部的程式碼。


Promise.prototype.finally()

finally方法用於指定不管 Promise 物件最後狀態如何,都會執行的操作。該方法是 ES2018 引入標準的。


Promise.all()

Promise.all方法用於將多個 Promise 例項,包裝成一個新的 Promise 例項。

var p = Promise.all([p1, p2, p3]);
  • 只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個陣列,傳遞給p的回撥函式
  • 只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的例項的返回值,會傳遞給p的回撥函式
  • 作為引數的 Promise 例項,自己定義了catch方法,那麼它一旦被rejected,並不會觸發Promise.all()的catch方法

參考/收藏:

相關文章