欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS手搓Promise的常見方法總結

 更新時間:2023年09月06日 08:37:57   作者:瑪拉_以琳  
這篇文章主要為大家詳細介紹了JavaScript中手寫Promise的一些常見方法,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下

1. 手搓 Promise

const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function MyPromise(fn) {
  // 保存初始化狀態(tài)
  var self = this;
  // 初始化狀態(tài)
  this.state = PENDING;
  // 用于保存 resolve 或者 rejected 傳入的值
  this.value = null;
  // 用于保存 resolve 的回調函數(shù)
  this.resolvedCallbacks = [];
  // 用于保存 reject 的回調函數(shù)
  this.rejectedCallbacks = [];
  // 狀態(tài)轉變?yōu)?resolved 方法
  function resolve(value) {
    // 判斷傳入元素是否為 Promise 值,如果是,則狀態(tài)改變必須等待前一個狀態(tài)改變后再進行改變
    if (value instanceof MyPromise) {
      return value.then(resolve, reject);
    }
    // 保證代碼的執(zhí)行順序為本輪事件循環(huán)的末尾
    setTimeout(() => {
      // 只有狀態(tài)為 pending 時才能轉變,
      if (self.state === PENDING) {
        // 修改狀態(tài)
        self.state = RESOLVED;
        // 設置傳入的值
        self.value = value;
        // 執(zhí)行回調函數(shù)
        self.resolvedCallbacks.forEach(callback => {
          callback(value);
        });
      }
    }, 0);
  }
  // 狀態(tài)轉變?yōu)?rejected 方法
  function reject(value) {
    // 保證代碼的執(zhí)行順序為本輪事件循環(huán)的末尾
    setTimeout(() => {
      // 只有狀態(tài)為 pending 時才能轉變
      if (self.state === PENDING) {
        // 修改狀態(tài)
        self.state = REJECTED;
        // 設置傳入的值
        self.value = value;
        // 執(zhí)行回調函數(shù)
        self.rejectedCallbacks.forEach(callback => {
          callback(value);
        });
      }
    }, 0);
  }
  // 將兩個方法傳入函數(shù)執(zhí)行
  try {
    fn(resolve, reject);
  } catch (e) {
    // 遇到錯誤時,捕獲錯誤,執(zhí)行 reject 函數(shù)
    reject(e);
  }
}
MyPromise.prototype.then = function(onResolved, onRejected) {
  // 首先判斷兩個參數(shù)是否為函數(shù)類型,因為這兩個參數(shù)是可選參數(shù)
  onResolved =
    typeof onResolved === "function"
      ? onResolved
      : function(value) {
          return value;
        };
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : function(error) {
          throw error;
        };
  // 如果是等待狀態(tài),則將函數(shù)加入對應列表中
  if (this.state === PENDING) {
    this.resolvedCallbacks.push(onResolved);
    this.rejectedCallbacks.push(onRejected);
  }
  // 如果狀態(tài)已經凝固,則直接執(zhí)行對應狀態(tài)的函數(shù)
  if (this.state === RESOLVED) {
    onResolved(this.value);
  }
  if (this.state === REJECTED) {
    onRejected(this.value);
  }
};

2. 手搓 Promise.then

then 方法返回一個新的 promise 實例,為了在 promise 狀態(tài)發(fā)生變化時(resolve / reject 被調用時)再執(zhí)行 then 里的函數(shù),我們使用一個 callbacks 數(shù)組先把傳給then的函數(shù)暫存起來,等狀態(tài)改變時再調用。

那么,怎么保證后一個 **then** 里的方法在前一個 **then**(可能是異步)結束之后再執(zhí)行呢?

我們可以將傳給 then 的函數(shù)和新 promise 的 resolve 一起 push 到前一個 promise 的 callbacks 數(shù)組中,達到承前啟后的效果:

  • 承前:當前一個 promise 完成后,調用其 resolve 變更狀態(tài),在這個 resolve 里會依次調用 callbacks 里的回調,這樣就執(zhí)行了 then 里的方法了
  • 啟后:上一步中,當 then 里的方法執(zhí)行完成后,返回一個結果,如果這個結果是個簡單的值,就直接調用新 promise 的 resolve,讓其狀態(tài)變更,這又會依次調用新 promise 的 callbacks 數(shù)組里的方法,循環(huán)往復。。如果返回的結果是個 promise,則需要等它完成之后再觸發(fā)新 promise 的 resolve,所以可以在其結果的 then 里調用新 promise 的 resolve
then(onFulfilled, onReject){
    // 保存前一個promise的this
    const self = this; 
    return new MyPromise((resolve, reject) => {
      // 封裝前一個promise成功時執(zhí)行的函數(shù)
      let fulfilled = () => {
        try{
          const result = onFulfilled(self.value); // 承前
          return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //啟后
        }catch(err){
          reject(err)
        }
      }
      // 封裝前一個promise失敗時執(zhí)行的函數(shù)
      let rejected = () => {
        try{
          const result = onReject(self.reason);
          return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
        }catch(err){
          reject(err)
        }
      }
      switch(self.status){
        case PENDING: 
          self.onFulfilledCallbacks.push(fulfilled);
          self.onRejectedCallbacks.push(rejected);
          break;
        case FULFILLED:
          fulfilled();
          break;
        case REJECT:
          rejected();
          break;
      }
    })
   }

注意:

  • 連續(xù)多個 then 里的回調方法是同步注冊的,但注冊到了不同的 callbacks 數(shù)組中,因為每次 then 都返回新的 promise 實例(參考上面的例子和圖)
  • 注冊完成后開始執(zhí)行構造函數(shù)中的異步事件,異步完成之后依次調用 callbacks 數(shù)組中提前注冊的回調

3. 手搓 Promise.all

1) 核心思路

  • 接收一個 Promise 實例的數(shù)組或具有 Iterator 接口的對象作為參數(shù)
  • 這個方法返回一個新的 promise 對象,
  • 遍歷傳入的參數(shù),用Promise.resolve()將參數(shù)"包一層",使其變成一個promise對象
  • 參數(shù)所有回調成功才是成功,返回值數(shù)組與參數(shù)順序一致
  • 參數(shù)數(shù)組其中一個失敗,則觸發(fā)失敗狀態(tài),第一個觸發(fā)失敗的 Promise 錯誤信息作為 Promise.all 的錯誤信息。

2)實現(xiàn)代碼

一般來說,Promise.all 用來處理多個并發(fā)請求,也是為了頁面數(shù)據構造的方便,將一個頁面所用到的在不同接口的數(shù)據一起請求過來,不過,如果其中一個接口失敗了,多個請求也就失敗了,頁面可能啥也出不來,這就看當前頁面的耦合程度了

function promiseAll(promises) {
  return new Promise(function(resolve, reject) {
    if(!Array.isArray(promises)){
        throw new TypeError(`argument must be a array`)
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedResult = [];
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(promises[i]).then(value=>{
        resolvedCounter++;
        resolvedResult[i] = value;
        if (resolvedCounter == promiseNum) {
            return resolve(resolvedResult)
          }
      },error=>{
        return reject(error)
      })
    }
  })
}
// test
let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
promiseAll([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
})

4. 手搓 Promise.race

該方法的參數(shù)是 Promise 實例數(shù)組, 然后其 then 注冊的回調方法是數(shù)組中的某一個 Promise 的狀態(tài)變?yōu)?fulfilled 的時候就執(zhí)行. 因為 Promise 的狀態(tài)只能改變一次, 那么我們只需要把 Promise.race 中產生的 Promise 對象的 resolve 方法, 注入到數(shù)組中的每一個 Promise 實例中的回調函數(shù)中即可.

Promise.race = function (args) {
  return new Promise((resolve, reject) => {
    for (let i = 0, len = args.length; i < len; i++) {
      args[i].then(resolve, reject)
    }
  })
}

到此這篇關于JS手搓Promise的常見方法總結的文章就介紹到這了,更多相關JS Promise內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家

相關文章

  • JS中的繼承操作實例總結

    JS中的繼承操作實例總結

    這篇文章主要介紹了JS中的繼承操作,結合實例形式總結分析了JS中的原型鏈繼承、構造函數(shù)繼承、組合繼承、class繼承等常見繼承操作實現(xiàn)技巧,需要的朋友可以參考下
    2020-06-06
  • JS正則截取兩個字符串之間及字符串前后內容的方法

    JS正則截取兩個字符串之間及字符串前后內容的方法

    這篇文章主要介紹了JS正則截取兩個字符串之間及字符串前后內容的方法,結合實例形式簡單分析了JS正則截取字符串操作的常用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2017-01-01
  • JavaScript中令你抓狂的魔術變量

    JavaScript中令你抓狂的魔術變量

    JavaScript中令你抓狂的魔術變量...
    2006-11-11
  • uploadify在Firefox下丟失session問題的解決方法

    uploadify在Firefox下丟失session問題的解決方法

    在用uploadify上傳插件時遇到了一個問題,在讀session時認為沒有權限而被攔截了,后來在后臺打印登錄時產生session的id和上傳時讀取session的id,解決方法如下,感興趣的朋友可以了解下
    2013-08-08
  • 純HTML5制作圍住神經貓游戲-附源碼下載

    純HTML5制作圍住神經貓游戲-附源碼下載

    圍住神經貓游戲是一款基于html5、jquery、typescript等技術開發(fā)的游戲,非常好玩,感興趣的朋友快來圍觀吧,體驗一把,下面給大家分享使用html5如何制作圍住神經貓游戲-附源碼下載,有需要的朋友可以參考下
    2015-08-08
  • Bootstrap CSS布局之按鈕

    Bootstrap CSS布局之按鈕

    這篇文章主要介為大家詳細紹了Bootstrap CSS布局之按鈕的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 微信小程序實現(xiàn)文本輸入彈窗

    微信小程序實現(xiàn)文本輸入彈窗

    這篇文章主要為大家詳細介紹了微信小程序實現(xiàn)文本輸入彈窗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • js實現(xiàn)文本上下來回滾動

    js實現(xiàn)文本上下來回滾動

    本文主要分享了js實現(xiàn)文本上下來回滾動的示例代碼。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • 關于刪除時的提示處理(確定刪除嗎)

    關于刪除時的提示處理(確定刪除嗎)

    在刪除時為了提醒用戶刪除數(shù)據的不可恢復一般都會有提示處理的,通常會使用js做到這一點,下面有個不錯的示例,感興趣的朋友可以參考下
    2013-11-11
  • javascript數(shù)組中的reduce方法和pop方法

    javascript數(shù)組中的reduce方法和pop方法

    這篇文章主要介紹了javascript數(shù)組中的reduce方法和pop方法,文章內容介紹詳細,具有一定的參考價值需要的小伙伴可以參考一下,希望對你的學習有所幫助
    2022-03-03

最新評論