在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
先不談語法,下面先來一個實例,創建感性的認識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>
打印結果以下所示:
jquery
能夠發現,
Promise
經過簡單的鏈式調用就能獲得以前多層回調才能達成的效果;並且從代碼的結構來看,有效地減少了各個請求之間的耦合;es6
別的不談,先打印一下 Promise
, console.dir(Promise)
, 看看它到底是哪號人物:ajax
原來
Promise
自己是一個構造函數,本身身上有all
、reject
、resolve
這幾個的方法,在其prototype
上有then
、catch
這兩個方法。那麼用Promise new出來的對象也會有then
、catch
這兩個方法。json
一、咱們發現,在 new Promise(function(resolve,reject){})
裏傳了兩個方法 resolve
、 reject
做爲參數,這兩個方法一般會在函數的回調裏被用到。一旦執行到resolve()
或者 reject()
,那麼這個函數會中止執行,而後觸發後面的 then()
或者 catch()
方法。準確一點來講,執行到resolve()
會觸發 then()
方法,執行到 reject()
會觸發 catch()
方法。api
二、resolve
和 reject
方法裏能夠傳入參數 ,就像 resolve(data)
和 reject(data)
。 若是這樣作 ,那麼在後面的 then()
或者 catch()
裏傳入一個帶參數的函數 , 就像 then(function(data){})
或者 catch(function(data){})
, 就能獲得 data
的數據 。跨域
三、說的再專業一些,Promise
對象有三種狀態,他們分別是:promise
這三種狀態不受外界影響,並且狀態只能從 pending
改變爲 resolved
或者rejected
,而且不可逆。在 Promise
對象的構造函數中,resolve
和 reject
就是用來處理Promise的狀態變化。
通常來講,調用 resolve
或 reject
之後,Promise 的使命就完成了,後繼操做應該放到 then
或者 catch
方法裏面,而不該該直接寫在 resolve()
或 reject()
的後面 (事實的狀況是,resolve()
或 reject()
的後面的代碼也不會執行)。
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()
給包起來
then()
函數的返回值必定是 Promise
對象還須要注意的的是,then()
函數的返回值必定是 Promise
對象,哪怕手動 return
一個值也無濟於事,以下面的代碼,照樣能運行成功:
a().then(function (){console.log("hello");return 1}).then(b) ;
這也解釋了爲何咱們能夠鏈式調用 then()
函數。
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
執行較快,Promise
的 then()
將得到結果 'P1'
。 p2
仍在繼續執行,但執行結果將被丟棄。
若是咱們組合使用Promise,就能夠把不少異步任務以並行和串行的方式組合起來執行。