你瞭解Promise麼

 

ECMAScript 6.0(es6)已經出來三年多了,相對es5,es6有不少新特性值得咱們去探究,其中Promise對象能夠說真的是頗有趣呢!笑哭.jpges6

Promise是什麼?他但是對象啊。你能親手new一個promise,而後讓他爲你作他能作到的事情,就算作不到,你還能給他加技能,想一想就很開心。數組

js是一門神奇的語言,他成功作到了把函數做爲參數。promise

下面的代碼很容易理解的:異步

var wait=function (time,callback) {
    setTimeout(function () {
        callback();
    },time)
};
wait(300,function () {
  console.log('等300ms我該作點啥呢?');
  //todo
})

 這裏的wait是個函數,它接收兩個參數,其中的callback就是一個函數。函數

這時候你是否是想說,回調用着還蠻帶勁的,別別別,當你遇到多重回調你會瘋掉的,前方高能,請作好一級戰鬥準備:es5

 var fun=function (callback1,callback2,callback3) {
        var data=1;
        setTimeout(function () {
            console.log('first:'+data);
            callback1(callback2,callback3,data)
        },1000)
    };
    var callback1=function (callback2,callback3,data) {
        setTimeout(function () {
            console.log('second:'+data);
            callback2(callback3,data)
        },1000)
    };
    var callback2=function (callback3,data) {
        setTimeout(function () {
            console.log('third:'+data);
            callback3(data)
        },1000)
    };
    var callback3=function (data) {
        setTimeout(function () {
            console.log('firth:'+data);
        },1000)
    };
    fun(callback1,callback2,callback3);

 

怎麼樣?驚不驚喜意不意外開不開心?就爲了傳個數據,就寫了四個函數,這特麼還能不能愉快的寫代碼了?spa

別急,這時候能夠有請咱們的Promise閃亮登場了。3d

且看下面一段代碼:code

var fun = function () {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                console.log('first:1');
                resolve('1')
            }, 1000)
        })
    };
    fun()
        .then(function (data) {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log('second'+data);
                    resolve(data)
                }, 1000)
            })
        })
        .then(function (data) {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log('third'+data);
                    resolve(data)
                }, 1000)
            })
        })
        .then(function (data) {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log('firth'+data);
                    resolve(data)
                }, 1000)
            })
        })

 

 怎麼樣,這一波鏈式操做是否是看起來舒服多了?舒服是舒服,就是有點兒不理解。那麼咱們就來一點點分析。對象

上面的代碼中:fun但是一個正經的函數,它的返回值是一個promise對象。咱們看到,promise對象還有一個then屬性,這個then是作什麼的呢,咱們後面會介紹。

promise就是一個表明了異步操做最終完成或者失敗的對象,既然promise是個對象,那他天然有本身的構造函數。promise的構造函數接受一個函數參數,這個函數有兩個參數,都是由js引擎提供,不須要本身去實現的。

第一個參數resolve(固然你命名成阿貓阿狗都行的)表示將Promise的狀態置爲fullfiled,reject是將Promise的狀態置爲rejected。這麼說可能有些晦澀難懂,其實吧,他們都是函數,這個函數何時執行呢?這取決於你。不過咱們約定俗成的作法是,在異步操做執行成功的時候,調用resolve,在異步操做執行失敗的時候調用reject。resolve和reject都要結合promise的then屬性來使用,then是一個函數,他的兩個參數分別對應promise的resolve和reject。

 

這段代碼的執行結果以下圖(每隔一秒輸出一行):

 

上面只驗證了resolve,咱們再來驗證下reject:

可能你會問,這並非異步操做啊?對的,這確實不是異步操做,這只是爲了驗證promise構造函數裏面的resolve和reject與then屬性的回調函數對應關係,你甚至能夠這麼寫:

到這裏,想必你已經對Promise已經有了大體的瞭解,沒錯,promise就是一個普通的擁有着衆多屬性的對象,那麼咱們繼續看看promise原型上的方法吧(哈?你問什麼是原型,那麼出門右拐,說不定能找到原型的介紹~)。

一、then

  爲promise實例提供狀態改變時的回調函數。(前面已經介紹了,這裏就不繼續廢話了)

二、catch

  咱們都知道如下寫法:

 try{
        //somecode
    }catch(error){
        
    }

   普通的catch的做用是用來捕獲try裏面的代碼塊執行過程當中的異常或錯誤,若是「somecode」裏面有錯誤,不捕獲的話就會影響後續的代碼執行,這樣就可能對總體代碼形成創傷。

  和普通catch同樣,Promise原型上的catch方法能捕獲到resolve裏面的異常,舉個栗子:

new Promise(function (resolve, reject) {
            setTimeout(function () {
                console.log('first:1');
                resolve('1')
            }, 1000)
        }).then(function(data){
             console.log(someVal);
        }) .catch(function(reason){
            console.log('出錯了:');
            console.log(reason);
        });    

  來看下控制檯執行結果:

  

  能夠看到,Promise的catch與普通的catch方法有着類似的功能。

  再來看一個栗子:

new Promise(function (resolve, reject) {
            setTimeout(function () {
                reject('1')
            }, 1000)
        }).then(function(data){
             console.log(someVal);
        }) .catch(function(data){
            console.log(data);
        });   

  執行結果以下:

  

  因此說,catch的回調能夠當成reject即then的第二個函數來使用。

三、finally

  finally的字面意思是最終的,在promise對象上表示這個對象最終執行的方法,就是說,不論是resolve仍是reject,最終都會進finally方法。

  來看代碼:

  

new Promise(function (resolve, reject) {
    setTimeout(()=>{resolve(1);},1000)
    setTimeout(()=>{reject(2);},2000)
})
    .then(result => {console.log(result)})
    .catch(error => {console.log(error)})
    .finally(() => {console.log('finally')});

 

  執行結果以下:

  

  在這個栗子中,Promise中的狀態爲fulfilled,但在執行了resolve方法後,仍是輸出了‘finally’。

  其實:finally()方法返回一個promise對象,在執行then()和catch()後都會執行finally指定的回調函數,避免一樣的代碼在then和catch中都寫一次,什麼意思呢?且看:

new Promise(function (resolve, reject) {
    setTimeout(()=>{resolve(1);},1000)
    setTimeout(()=>{reject(2);},2000)
})
    .then(result => {console.log('我是異步操做以後必需要執行的代碼')})
    .catch(error => {console.log('我是異步操做以後必需要執行的代碼')})

輸出以下:

  

  其實,針對上述代碼,finally就能搞定,你只須要這樣寫就行:

new Promise(function (resolve, reject) {
    setTimeout(()=>{resolve(1);},1000)
    setTimeout(()=>{reject(2);},2000)
})
    .finally(() => {console.log('我是異步操做以後必需要執行的代碼')})

  不信你就執行看看啊。

講完了Promise原型上的方法,接下來咱們來說講Promise構造函數內的方法。

一、all

  

Promise.all([new Promise(function (p1, p2) {
  setTimeout(() => {
    console.log(1);
    p1(1)
  }, 1000)
}),
  new Promise(function (p1, p2) {
    setTimeout(() => {
      console.log(2);
      p1(2)
    }, 2000)
  }), new Promise(function (p1, p2) {
    setTimeout(() => {
      console.log(3);
      p1(3)
    }, 3000)
  })]).then(function (results) {
  console.log(results);
})

先看看執行結果:

咱們來分析一下:all方法接收一個數組做爲參數,這個數組的元素全是Promise實例,當這三個Promise的狀態都改變時,會進入到all對應的Promise構造函數的then方法,這個then的回調函數參數則是all方法接收的Promise傳遞的數據封裝後的數組。

也就是說,有了all,你能夠並行執行多個異步操做,all會把全部異步操做的結果放進一個數組中傳給then。這在不少場景下都適用。好比說某個頁面,ABC資源的加載的都是異步的,且之間沒有依賴關係,咱們須要在ABC資源都加載完成後才執行一些神操做,那麼這時候all就能夠解決這個問題。

二、race

  race和all的代碼格式差很少,怎麼辦,我懶得貼代碼了,口述吧。

  前面咱們說all時等全部的異步操做完成後會進入then的回調,這裏的race就不同了,它表示只要有異步操做執行完了,就會就如then回調,且不影響其餘的異步操做的執行。

  哎,仍是貼貼一段代碼吧。

  

  看到了吧,這裏輸出了兩個1,第二個1時執行最快的那個Promise傳個race的then回調了。那麼race有什麼用了,它做用大着呢,它能夠能夠給某個異步操做設置超時時間。好比說:

  

三、resolve

 這時候你是否是懵逼了,怎麼構造函數內部還有resolve方法,他不是構造函數的回調的參數麼?哈哈,沒辦法,Promise創始人讓它有的,咱們沒辦法阻止的。

  resolve方法返回一個以給定值解析後的Promise對象。

   

  也就是說,resolve會返回一個Promise的實例,這個實例的then方法的第一個回調函數能獲取到resolve傳過去的數據,進而對數據進行操做。

四、reject

  與resolve差很少,這裏就不細講了。

呼,總算寫完了~~~~~~~~

相關文章
相關標籤/搜索