我的Promise祕密初探之小試牛刀

單殺一條龍發表於2018-01-15

一、前言概述

在前端開發中,相信很多讀者都使用過AJAX,這種比較? 逼的非同步處理方式,確實在一定程度上方便和簡化了我們的某些需求,但有時候也會遇到在一個操作中,會需要多個非同步請求的情況,在以往的處理中,比如筆者就曾做過2個及多個AJAX層層巢狀著處理的方式,這種方式,在當時看上去也可以滿足一般的需求,但看著彆扭,總覺得哪裡不爽;

$.ajax({
    cache: false,
    type: 'POST',
    url: url1,
    dataType: 'json', 
    success: function (data) {
        $.ajax({
            cache: false,
            type: 'POST',
            url:url2,
            data: { para: list},
            dataType: 'json',
            success: function(result) {
                ......
            }
        })
    }
})
複製程式碼

如上,魔鬼巢狀;

很快,隨著ES6的釋出,Promise橫空出世,之前多個AJAX多層巢狀的處理方式,看上去顯得那麼的low,如此的惡劣不堪,反觀Promise,高階大氣上檔次-------哈哈,是不是有點喜新厭舊的嫌疑啊------瞬間,讓我喜歡上了,有點一見鍾情的趕腳?

整個就是一大方優雅的典範啊:

readFile(filename).then(function (data) {
    return data;
}).then(function (data) {
    return readFile(data);
}).then(function (data) {
    console.log(data);
}).catch(function(err){
    ......
});
複製程式碼

二、原理淺析

  1. Promise 名如其實,Promise本意是承諾,在程式中的意思就是承諾我過一段時間後會給你一個結果。 什麼時候會用到過一段時間?答案是非同步操作,非同步是指可能比較長時間才有結果的才做,例如網路請求、讀取本地檔案等;

    在這個過程中,Promise會經歷三個狀態:

  • Pending Promise物件例項建立時候的初始狀態
  • Fulfilled 可以理解為成功的狀態
  • Rejected 可以理解為失敗的狀態

then 方法就是用來指定Promise 物件的狀態改變時確定執行的操作,resolve 時執行第一個函式(onFulfilled),reject 時執行第二個函式(onRejected)

  1. 示例分析:
let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        if(Math.random()>0.5)
            resolve('This is resolve!');
        else
            reject('This is reject!');
    }, 1000);
});
promise.then(Fulfilled,Rejected)
複製程式碼
  • 構造一個Promise例項需要給Promise建構函式傳入一個函式。
  • 傳入的函式需要有兩個形參,兩個形參都是function型別的引數。
    • 第一個形參執行後會讓Promise例項處於resolve狀態,所以我們一般給第一個形參命名為resolve,使 Promise 物件的狀態改變成成功,同時傳遞一個引數用於後續成功後的操作
    • 第一個形參執行後會讓Promise例項處於reject狀態,所以我們一般給第一個形參命名為reject,將 Promise 物件的狀態改變為失敗,同時將錯誤的資訊傳遞到後續錯誤處理的操作

三、小試牛刀

經過一些時間的學習和摸索,筆者在ES6自帶的Promise的基礎上,實現了對其all、race、resolve、reject的功能模擬;

  1. Promise.all
  • 引數:接受一個陣列,陣列內都是Promise例項。
  • 返回值:返回一個Promise例項,這個Promise例項的狀態轉移取決於引數的Promise例項的狀態變化。當引數中所有的例項都處於resolve狀態時,返回的Promise例項會變為resolve狀態。如果引數中任意一個例項處於reject狀態,返回的Promise例項變為reject狀態。
  • 程式碼如下
Promise.all = function(promises){
 return new Promise(function(resolve,reject){
   let done = gen(promises.length,resolve);
   for(let i=0;i<promises.length;i++){
     promises[i].then(function(data){
       done(i,data);
     },reject);
   }
 });
}
複製程式碼
  1. Promise.race
  • 引數:接受一個陣列,陣列內都是Promise例項
  • 返回值:返回一個Promise例項,這個Promise例項的狀態轉移取決於引數的Promise例項的狀態變化。當引數中任何一個例項處於resolve狀態時,返回的Promise例項會變為resolve狀態。如果引數中任意一個例項處於reject狀態,返回的Promise例項變為reject狀態。
  • 程式碼如下:
Promise.race = function(promises){
  return new Promise(function(resolve,reject){
    for(let i=0;i<promises.length;i++){
      promises[i].then(resolve,reject);
    }
  });
}
複製程式碼
  1. Promise.resolve
  • 該方法返回一個Promise例項,這個例項處於resolve狀態。 會根據傳遞的引數不同而有不同的功能:
  • 當引數是值(物件、陣列、字串等)型別的:作為resolve傳遞出去的值;
  • 當引數是Promise例項:則原封不動返回;
  • 程式碼如下:
//返回一個立刻成功的promise
//但該方法,需要傳入一個promise,但你只有一個普通的值,你就可以通過這個方法
//把這個普通的值(string number object)轉成一個promise物件
Promise.resolve = function(value){
  return new Promise(function(resolve){
    resolve(value);
  });
}
複製程式碼
  1. Promise.reject
  • 該方法返回一個Promise例項,這個例項處於reject狀態。
  • 引數一般就是丟擲的錯誤資訊。
  • 程式碼如下:
//返回一個立刻失敗的promise
Promise.reject = function(reason){
  return new Promise(function(resolve,reject){
    reject(reason);
  });
}
複製程式碼

四、小結

以上就是在下對前端經常遇到的非同步處理方式的前認與後知;本人自知才疏學淺,如果有一些理解的有失偏頗之處,歡迎各位隨時拍磚與指正~!

當然,如果對您還有點作用的話,還望您評論鼓勵,以資我繼續前行,小可不勝感激~!

相關文章