理解ES6中的Promise

1、Promise的做用

在ajax請求數據的過程當中,咱們能夠異步拿到咱們想要的數據,而後在回調中作相應的數據處理。
這樣作看上去並無什麼麻煩,可是若是這個時候,咱們還須要作另一個ajax請求,這個新的ajax請求的其中一個參數,得從上一個ajax請求中獲取,這個時候咱們就須要在回調函數中再寫一個異步請求,而後在這個異步函數的回調函數裏在寫相應的數據處理。要是連續嵌套個三四層,每每就很噁心了。
寫起來就像下面這樣:javascript

$.ajax({
    type:'get',
    url:'url_1', 
    data: 'data'
    success : function(res){
        //相應的數據處理
        var data = res.data
        $.ajax({
            type:'get',
            url:'url_2', 
            data: data
            success : function(res){
                //相應的數據處理
                $.ajax({
                    type:'get',
                    url:'url_3', 
                    data: data
                    success : function(res){
                        //相應的數據處理
                    }
                })
            }
        })
    }
})

在這種狀況下Promise就能發揮它的威力了;html

2、來一個實例

先不談語法,下面先來一個實例,創建感性的認識java

<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
    </head>
    <body>
    </body>
    <script>
        function a(data){
            return new Promise(function(resolve,reject){
                console.log("我是從上一個回調函數裏傳過來的數據",data) ;
                $.ajax({
                    type:'post',
                    dataType: 'jsonp',
                    url:'http://api.money.126.net/data/feed/0000001,1399001',   //jsonp跨域調用上證與深證的股票指數
                    data:{
                    },
                    success : function(res){
                        console.log(res) ;
                        resolve(res) ;
                    },
                    error:function(res){
                        console.log("Error:") ;
                        console.log(res) ;
                        reject(res) ;
                    }
                })
            });
        }
        function b(data){
            return new Promise(function(resolve,reject){
                console.log("我是從上一個回調函數裏傳過來的數據",data) ;
                $.ajax({
                    type:'post',
                    dataType: 'jsonp',
                    url:'https://api.douban.com/v2/movie/top250',  //跨域調用豆top250的電影
                    success : function(res){
                        console.log(res) ;
                        resolve(res) ;
                    },
                    error:function(res){
                        console.log("Error:") ;
                        console.log(res) ;
                        reject(res)
                    }
                })
            });
        }
        a().then(b).then(a).then(b).catch(function(a){console.log("final Error:",a)}) ;
    </script>
</html>

打印結果以下所示:
Alt textjquery

能夠發現,Promise 經過簡單的鏈式調用就能獲得以前多層回調才能達成的效果;並且從代碼的結構來看,有效地減少了各個請求之間的耦合;es6

3、深刻Promise

別的不談,先打印一下 Promise , console.dir(Promise) , 看看它到底是哪號人物:ajax

Alt text

原來 Promise 自己是一個構造函數,本身身上有 allrejectresolve 這幾個的方法,在其 prototype 上有 thencatch 這兩個方法。那麼用Promise new出來的對象也會有 thencatch 這兩個方法。json

4、注意上面實例中的resolve與reject

一、咱們發現,在 new Promise(function(resolve,reject){}) 裏傳了兩個方法 resolvereject 做爲參數,這兩個方法一般會在函數的回調裏被用到。一旦執行到resolve() 或者 reject() ,那麼這個函數會中止執行,而後觸發後面的 then() 或者 catch() 方法。準確一點來講,執行到resolve() 會觸發 then() 方法,執行到 reject() 會觸發 catch() 方法。api

二、resolvereject 方法裏能夠傳入參數 ,就像 resolve(data)reject(data) 。 若是這樣作 ,那麼在後面的 then() 或者 catch() 裏傳入一個帶參數的函數 , 就像 then(function(data){}) 或者 catch(function(data){}) , 就能獲得 data 的數據 。跨域

三、說的再專業一些,Promise 對象有三種狀態,他們分別是:promise

  • pending: 等待中,或者進行中,表示尚未獲得結果
  • resolved(Fulfilled): 已經完成,表示獲得了咱們想要的結果,能夠繼續往下執行
  • rejected: 也表示獲得結果,可是因爲結果並不是咱們所願,所以拒絕執行

這三種狀態不受外界影響,並且狀態只能從 pending 改變爲 resolved 或者rejected ,而且不可逆。在 Promise 對象的構造函數中,resolvereject 就是用來處理Promise的狀態變化。
通常來講,調用 resolvereject 之後,Promise 的使命就完成了,後繼操做應該放到 then 或者 catch 方法裏面,而不該該直接寫在 resolve()reject() 的後面 (事實的狀況是,resolve()reject() 的後面的代碼也不會執行)

5、new Promise() 裏的函數是馬上執行的

須要注意的的是,new Promise() 裏的函數是馬上執行的 ,也就是說 ,當你執行下面這段代碼時,就已經開始執行異步請求了:

<script>
new Promise(function(resolve,reject){
    $.ajax({
        type:'post',
        dataType: 'jsonp',
        url:'http://api.money.126.net/data/feed/0000001,1399001',
        data:{
        },
        success : function(res){
            console.log(res) ;
            resolve(res) ;
        },
        error:function(res){
            reject(res) ;
        }
    })
});
</script>

這也是爲何,在上面第二段的實例中,須要用 a()b() 函數把 new Promise() 給包起來

6、then() 函數的返回值必定是 Promise 對象

還須要注意的的是,then() 函數的返回值必定是 Promise 對象,哪怕手動 return 一個值也無濟於事,以下面的代碼,照樣能運行成功:

a().then(function (){console.log("hello");return 1}).then(b) ;

這也解釋了爲何咱們能夠鏈式調用 then() 函數。

7、Promise.all()Promise.race()的用法

想要從兩個不一樣的 ajax 請求裏分別得到信息,這兩個任務是能夠並行執行的,就能夠用 Promise.all() 實現:

<script>
var p1 = function(){
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
} ;
var p2 = function(){
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 1000, 'P2');
    });
} ;
// 同時執行p1和p2,並在它們都完成後執行then
var start = function(){
    Promise.all([p1(), p2()]).then(function (results) {
        console.log(results); // 得到一個Array: ['P1', 'P2']
    });
}
</script>

有些時候,多個異步任務是爲了容錯。好比,分別發兩個不一樣的 ajax 請求讀取用戶的我的信息,只須要得到先返回的結果便可,這種狀況下,就能夠用Promise.race() 實現:

<script>
var p1 = function(){
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
} ;
var p2 = function(){
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 1000, 'P2');
    });
} ;
var start = function(){
    Promise.all([p1(), p2()]).then(function (results) {
        console.log(results); // 'P1'
    });
}
</script>

因爲 p1 執行較快,Promisethen() 將得到結果 'P1'p2 仍在繼續執行,但執行結果將被丟棄。

若是咱們組合使用Promise,就能夠把不少異步任務以並行和串行的方式組合起來執行。

參考文獻:
阮一峯ES6入門
廖雪峯的官方網站
sitepoint
"呂大豹"的博客園
原文地址:
王玉略的我的網站

相關文章
相關標籤/搜索