溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript怎么實現(xiàn)簡易的Promise對象

發(fā)布時間:2022-12-01 10:07:28 來源:億速云 閱讀:121 作者:iii 欄目:開發(fā)技術(shù)

這篇“JavaScript怎么實現(xiàn)簡易的Promise對象”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript怎么實現(xiàn)簡易的Promise對象”文章吧。

前言

實現(xiàn)一個簡易的Promise對象,我們首先要了解幾個相關(guān)的知識點:

Promise對象的狀態(tài): pending(進行中)、fulfilled(已成功)和rejected(已失?。?。只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。

Promise的參數(shù): Promise構(gòu)造函數(shù)接收一個函數(shù)作為參數(shù),函數(shù)內(nèi)部有兩個參數(shù),分別是resolve和reject,這兩個參數(shù)是兩個函數(shù),由JS引擎提供,不需要我們部署。reslove函數(shù)的作用是將Promise對象的狀態(tài)由 'pending' 狀態(tài)變?yōu)?'resolved'狀態(tài)即('fulfilled'狀態(tài)),方便與參數(shù)名對應(yīng),reject函數(shù)的作用是將Promise對象的狀態(tài)由 'pending' 狀態(tài)變?yōu)?'rejected'狀態(tài)。

但是我們應(yīng)該注意的是,Promise對象的狀態(tài)一經(jīng)改變,就不再發(fā)生改變(即pending --> resolved || pending --> rejected 其中任意一種發(fā)生改變之后,Promise對象的狀態(tài)將不再發(fā)生改變)

Promise的基礎(chǔ)結(jié)構(gòu)與用法

 let p1 = new Promise((resolve, reject) => {
   resolve('成功');
   reject('失敗');
   throw('報錯');  //相當于reject()
 })

 console.log(p1);

讓我們看看三種狀態(tài)的打印的結(jié)果分別是什么吧

JavaScript怎么實現(xiàn)簡易的Promise對象

JavaScript怎么實現(xiàn)簡易的Promise對象

JavaScript怎么實現(xiàn)簡易的Promise對象

使用class類實現(xiàn)promise對象

class myPromise {
  constructor(executor) {
    this.status = 'pending'; // 變更promise的狀態(tài)
    this.value = null;
    
    executor(this.resolve, this.reject); // new 一個myPromise 得到的實例對象里面有兩個函數(shù)
  }

  resolve(value) {
    if (this.status !== 'pending') return;
    this.status = 'fulfilled'; // 變更promise的狀態(tài)
    this.value = value;
  }

  reject(reason) {
    if (this.status !== 'pending') return
    this.status = 'rejected';
    this.value = reason;
  }
}

貌似這么寫代碼邏輯也說得通,那么讓我們看一下實現(xiàn)的效果:

JavaScript怎么實現(xiàn)簡易的Promise對象

看到這里,不難想到我們的resolve和reject的兩個方法的this指向出現(xiàn)了問題,我們仔細看看不難發(fā)現(xiàn),這兩個方法被我們作為實參放到了構(gòu)造器函數(shù),此時this的指向是指向了構(gòu)造器函數(shù),而不是我們寫的myPromise這個構(gòu)造函數(shù)身上,那只需要bind顯示綁定一下this 的指向就可以解決了。

executor(this.resolve.bind(this), this.reject.bind(this))

JavaScript怎么實現(xiàn)簡易的Promise對象

并且myPromise的狀態(tài)一經(jīng)變更也不再改變,是不是有一點原裝Promise的味道了。但是在Promise里面還有一個錯誤捕捉機制,只要promise里面執(zhí)行的邏輯報錯了,就需要走reject邏輯,將錯誤拋出來,那我們只需要使用try catch來實現(xiàn)就可以。

try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error)
    }

這樣我們就實現(xiàn)了極簡版的Promise對象,但是通常情況下我們都是使用Promise對象來處理異步的問題,說到異步,那不得不提起Promise.prototype.then()這個方法了,then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調(diào)用另一個then方法。

then方法的第一個參數(shù)是`resolved狀態(tài)的回調(diào)函數(shù)`,第二個參數(shù)是`rejected狀態(tài)的回調(diào)函數(shù)`,它們都是可選的。

當promise的狀態(tài)為'fulfilled'會執(zhí)行第一個回調(diào)函數(shù),當狀態(tài)為'rejected'時執(zhí)行第二個回調(diào)函數(shù)。

必須等到Promise的狀態(tài)變更過一次之后,狀態(tài)為'fulfilled'或者'rejected',才去執(zhí)行then里面的邏輯。

.then支持鏈式調(diào)用,下一次.then受上一次.then執(zhí)行結(jié)果的影響。

知道以上這幾點,我們就可以嘗試如何實現(xiàn).then方法了

class myPromise {
  constructor(executor) {
    this.status = 'pending'; 
    this.value = null;
    this.onFulfilledCallbacks = []; // 用來保存成功的回調(diào)(處理異步)
    this.onRejectedCallbacks = []; // 用來保存失敗的回調(diào)(處理異步)
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error)
    }
  }

  resolve(value) {
    if (this.status !== 'pending') return;
    this.status = 'fulfilled';
    this.value = value;
    // 調(diào)用then里面的回調(diào)
    while (this.onFulfilledCallbacks.length) { // 當異步成功回調(diào)數(shù)組中存在回調(diào)函數(shù),那就執(zhí)行
      this.onFulfilledCallbacks.shift()(this.value)
    }
  }

  reject(reason) {
    if (this.status !== 'pending') return
    this.status = 'rejected';
    this.value = reason;
    while (this.onRejectedCallbacks.length) { // 當異步失敗回調(diào)數(shù)組中存在回調(diào)函數(shù),那就執(zhí)行
      this.onRejectedCallbacks.shift()(this.value)
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val  // 判斷.then的第一個參數(shù)是不是一個函數(shù),如果不是就直接作為結(jié)果返回
    onRejected = typeof onRejected === 'function' ? onRejected : val => { throw val } // 判斷.then的第二個參數(shù)是不是一個函數(shù),如果不是就直接作為錯誤返回

    var thenPromise = new myPromise((resolve, reject) => {  // 因為.then返回的是一個心的Promise對象

      const resolvePromise = callback => {  // 用于判斷回調(diào)函數(shù)的類型
        setTimeout(() => {   // 讓整個回調(diào)函數(shù)比同步代碼晚一點執(zhí)行,官方不是使用setTimeout實現(xiàn)
          try {
            const x = callback(this.value);
            if (x === thenPromise) {  // 你正在返回自身
              throw new Error('不允許返回自身!');
            }
            if (x instanceof myPromise) { // 返回的是一個Promise對象
              x.then(resolve, reject);
            } else { // 直接返回一個值,作為resolve的值,傳遞給下一個.then
              resolve(x);
            }
          } catch (error) {
            reject(error);
            throw new Error(error)
          }
        })
      }

      if (this.status === 'fulfilled') {
        resolvePromise(onFulfilled)
      } else if (this.status === 'rejected') {
        resolvePromise(onRejected)
      } else if (this.status === 'pending') {
        this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled));
        this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
      }
    })
    return thenPromise
  }
}

JavaScript怎么實現(xiàn)簡易的Promise對象

以上就是關(guān)于“JavaScript怎么實現(xiàn)簡易的Promise對象”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI