2021-03-13【技術(shù)】關(guān)于Promise中的resolve,reject,catch的理解

先來說一下Promise的三種狀態(tài)

pending - 進行中
fulfilled - 成功
rejected - 失敗

Promise對象,可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)。
但Promise對象的狀態(tài)不受外界影響,Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失?。?,只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài),這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。

狀態(tài)的改變(或者說決議)不可逆,一旦決議就不能再更改。
任何時候都可以得到這個結(jié)果,Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled 或者 從pending變?yōu)閞ejected,只要這兩種情況中的一種發(fā)生,其狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果,這時就稱為 resolved(已定型)。
如果改變已經(jīng)發(fā)生了,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果。
這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監(jiān)聽,是得不到結(jié)果的。


進階開始,讓我們手寫一個promise
概念: promise接受一個函數(shù) 有三種 狀態(tài) 倆個回調(diào)
寫一個構(gòu)造函數(shù)接收一個參數(shù) 有三種狀態(tài) 成功結(jié)果 失敗結(jié)果 成功回調(diào) 失敗 回調(diào)
構(gòu)造函數(shù)的原型有一個.then 方法 接收倆個參數(shù) 判斷狀態(tài) 如果成功調(diào)用 成功函數(shù) 失敗 調(diào)用失敗函數(shù) pending 就存起來。
代碼如下:

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

// promise接受一個函數(shù) 有三種 狀態(tài) 倆個回調(diào)
// 寫一個構(gòu)造函數(shù)接收一個參數(shù)  有三種狀態(tài),此外還有:成功結(jié)果 失敗結(jié)果 成功回調(diào) 失敗回調(diào)
// 構(gòu)造函數(shù)的原型有一個.then 方法 接收倆個參數(shù)  判斷狀態(tài) 如果成功調(diào)用 成功函數(shù) ;失敗 調(diào)用失敗函數(shù) pending 就存起來

function Promise (executor) {
  var _this = this
  this.state = PENDING  // 狀態(tài)
  this.value = undefined  // 成功結(jié)果
  this.reason = undefined;  // 失敗原因
  this.onFulfilled = [];//成功的回調(diào)
  this.onRejected = []; //失敗的回調(diào)

  function resolve (value) {
    if (_this.state === PENDING) {
      _this.state = FULFILLED
      _this.value = value
      _this.onFulfilled.forEach(fn => fn(value))
    }
  }
  function reject (reason) {
    if (_this.state === PENDING) {
      _this.state = REJECTED
      _this.reason = reason
      _this.onRejected.forEach(fn => fn(reason))
    }
  }
  try {
    executor(resolve, reject)
  } catch (e) {}
}

Promise.prototype.then = function (onFulfilled, onRejected) {
  if (this.state === FULFILLED) {
    typeof onFulfilled === 'function' && onFulfilled(_this.value)
  }
  if (this.state === REJECTED) {
    typeof onRejected === 'function' && onRejected(_this.reason)
  }
  if(this.state === PENDING){
    typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
    typeof onRejected === 'function' && this.onRejected.push(onRejected)
  } 
}

// module.exports = Promise;


var p = new Promise((resolve, reject)=>{
  setTimeout(()=>{
      resolve(4)
  }, 0)
})
p.then((res)=>{
  //4 res
  console.log(res, 'res')
})
p.then((res1)=>{
  //4 res1
  console.log(res1, 'res1')
})

一、對于resolve,reject簡單理解

我們先構(gòu)建一個Promise

//構(gòu)建Promise
var promise = new Promise(function (resolve, reject) {
    if (/* 異步操作成功 */) {
        resolve(data);
    } else {
        /* 異步操作失敗 */
        reject(error);
    }
});

這種方式類似構(gòu)建對象,使用new來構(gòu)建一個Promise。
Promise接受一個「函數(shù)」作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject。這兩個函數(shù)就是就是「回調(diào)函數(shù)」,由JavaScript引擎提供。

Promise實例生成以后,可以用then方法指定resolved狀態(tài)和reject狀態(tài)的回調(diào)函數(shù)。

//promise.then(onFulfilled, onRejected);
promise.then(function(data) {
  // do something when success
}, function(error) {
  // do something when failure
});

then方法會返回一個Promise。它有兩個參數(shù),分別為Promise從pending 變?yōu)?fulfilled和rejected時的回調(diào)函數(shù)(第二個參數(shù)非必選)。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)。

.catch()

該方法是.then(undefined, onRejected)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)。

promise.then(function(data) {
    console.log('success');
}).catch(function(error) {
    console.log('error', error);
});

/*******等同于*******/
promise.then(function(data) {
    console.log('success');
}).then(undefined, function(error) {
    console.log('error', error);
});

promise對象的錯誤,會一直向后傳遞,直到被捕獲。即錯誤總會被下一個catch所捕獲。then方法指定的回調(diào)函數(shù),若拋出錯誤,也會被下一個catch捕獲。catch中也能拋錯,則需要后面的catch來捕獲。

sendRequest('test.html').then(function(data1) {
    //do something
}).then(function (data2) {
    //do something
}).catch(function (error) {
    //處理前面三個Promise產(chǎn)生的錯誤
});

此處要注意,promise一旦resolve(即成功狀態(tài))了再拋錯,也不會變?yōu)閞ejected(失敗狀態(tài)),也就不會被catch了,代碼如下:

var promise = new Promise(function(resolve, reject) {
  resolve();
  throw 'error';
});

promise.catch(function(e) {
   console.log(e);      //This is never called-永遠不會被觸發(fā)
});

如果沒有使用catch方法指定處理錯誤的回調(diào)函數(shù),Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應

關(guān)于promise中reject和catch的問題
一、reject后的東西,一定會進入then中的第二個回調(diào),如果then中沒有寫第二個回調(diào),則進入catch

var p1=new Promise((resolve,rej) => {
    console.log('沒有resolve')
    //throw new Error('手動返回錯誤')
    rej('失敗了')
 })
 p1.then(data =>{
    console.log('data::',data);
 },err=> {
    console.log('err::',err)
 }).catch(
    res => {
    console.log('catch data::', res)
 })

結(jié)果為:

沒有resolve
err:: 失敗了

then中沒有第二個回調(diào)的情況

var p1=new Promise((resolve,rej) => {
    console.log('沒有resolve')
    //throw new Error('手動返回錯誤')
    rej('失敗了')

 })
 p1.then(data =>{
    console.log('data::',data);
 }).catch(
    res => {
    console.log('catch data::', res)
 })

結(jié)果為:

沒有resolve
catch data:: 失敗了

二、resolve的東西,一定會進入then的第一個回調(diào),肯定不會進入catch

var p1=new Promise((resolve,rej) => {
    console.log('resolve')
    //throw new Error('手動返回錯誤')
    resolve('成功了')

 })

 p1.then(data =>{
    console.log('data::',data);
 }).catch(
    res => {
    console.log('catch data::', res)
 })

結(jié)果為:

resolve
data:: 成功了

不會進入catch的情況,只要resolve(即成功)了,就算拋出err,也不會進入catch

 var p1=new Promise((resolve,rej) => {
    console.log('resolve')
    //throw new Error('手動返回錯誤')
    resolve('成功了')
 })

 p1.catch(
    res => {
    console.log('catch data::', res)
 })

結(jié)果:

resolve //即成功以后永遠不會進入catch

throw new Error 的情況和rej一樣,但是他倆只會有一個發(fā)生
另外,網(wǎng)絡異常(比如斷網(wǎng)),會直接進入catch而不會進入then的第二個回調(diào)

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

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

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