Promise小結

   Promise是異步裏面的一種解決方案,解決了回調嵌套的問題,es6將其進行了語言標準,贊成了用法,提供了`promise`對象, promise對象有三種狀態:pending(進行中) 、Resolved(已經完成)和Rejected(已失敗)javascript

ES6規定,Promise對象是一個構造函數,用來生成Promise實例。php

1
2
3
4
5
6
7
var  promise= new  Promise( function (resove,reject){
      if  ( /* 異步操做成功 */ ){
     resolve(value);
   else  {
     reject(error);
   }
})

Promise實例生成之後,能夠用then方法分別指定Resolved狀態和Reject狀態的回調函數。java

1
2
3
4
5
promise.then( function (value) {
   // success
},  function (error) {
   // failure
});

案例es6

1
2
3
4
5
6
7
var  promise= new  Promise( function (resolve,reject){
          console.log( 'promise' );
      })
      promise.then( function (){
         console.log( '我後執行' )
      })
      console.log( '我先執行' )<br><br> //上面代碼中,Promise新建後當即執行,因此首先輸出的是「Promise」。而後,<code>then</code>方法指定的回調函數,<br>//將在當前腳本全部同步任務執行完纔會執行,因此「我後執行」 最後輸出。

 ajaxajax

var  http = {
     get:  function (url) {
         var  promise =  new  Promise( function (resolve, reject) {
             $.ajax({
                 url: url,
                 method:  'get' ,
                 success:  function (data) {
                     resolve(data);
                 },
                 error:  function (xhr, statusText) {
                     reject(statusText);
                 }
             });
         });
         return  promise;
     }
};
http.get( 'solve.php' ).then( function (data) {
     return  data;
},  function (err) {
     return  Promise.reject( 'Sorry, file not Found.' );
}).then( function (data) {
     document.write(data);
},  function (err) {
     document.write(err);
});

複製代碼
 1      var getJSON=function(url){
 2         var promise=new Promise(function(resolve,reject){
 3             var xhr=new XMLHttpRequest();
 4             xhr.open('get',url);
 5             xhr.onreadystatechange=handler;
 6             xhr.send(null);
 7 
 8             function handler(){
 9                 if(this.readystate!==4){
10                     return;
11                 }
12                 if(this.status==200){
13                     resolve(this.responseText)
14                 }else{
15                     reject(new Error(this.statusText));
16                 }
17             }
18         })
19           return promise;
20      }
21     getJSON("/get.json").then(function(json) {
22       console.log('Contents: ' + json);
23     }, function(error) {
24       console.error('出錯了', error);
25     });
複製代碼

 

 

 

Promise三種狀態

pending、resolved、rejectedjson

使用語法

var promis = new Promise(function(resolve,reject){ $.ajax({ url:'/api/something.json', method:'get', datatype:'json', success:(res) =>{ resolve(res) }, error:(err)=>{ reject(err) } }) }) promis.then(function(res){ console.log(res) }).catch(function(err){ console.log(err) });

Promise.prototype.then()

鏈式調用,狀態變爲resolve
若是把下一步想要的東西return出去,便可讓下一個then使用api

var promise = new Promise(function(resolve,reject){ $.ajax({ url:'/api/poisearch.json', method:'get', datatype:'json', success:(res) =>{ resolve(res) }, error:(err)=>{ reject(err) } }) }) promise.then(function(res){ return res.data }).then(function(data){ return data.result; }).then(function(result){ console.log(result) });

上面的代碼還能夠借用箭頭函數簡寫成,極大提高了代碼的簡潔性和可讀性數組

promise.then(res => res.data) .then(data => data.result) .then(result => console.log(result));

Promise.prototype.catch()

若是異步操做拋出錯誤,狀態就會變爲Rejected,就會調用catch方法指定的回調函數,處理這個錯誤。promise

  1. 另外,then方法指定的回調函數,若是運行中拋出錯誤,也會被catch方法捕獲。
  2. 若是Promise狀態已經變成Resolved,再拋出錯誤是無效的。
  3. catch方法返回的仍是一個Promise對象,所以後面還能夠接着調用then方法。

Promise.all()

多個Promise實例,包裝成1個,有點相似Array.prototype.every()
用法:閉包

var p = Promise.all([p1, p2, p3]);
  1. 只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
  2. 只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

Promise.race()

多個Promise實例,包裝成1個,有點相似Array.prototype.some()

  1. p一、p二、p3其中一個狀態變成fulfilled,p的狀態就會變成fulfilled
  2. 那個率先改變的Promise實例的返回值,就傳遞給p的回調函數。

done()、finally()

 

 

 

 

 

 

 

 

 

 

 

新的ES6中引入了promise的概念,目的是讓回調更爲優雅。層層嵌套的回調會讓javascript失去美感和可讀性,同時javascript也推薦採用鏈式的方式去書寫函數調用。因而Promise就應運而生。Promise即承諾的意思,new一個Promise就是新建一個承諾。在新建一個承諾的時候你須要作兩件事情:

  1.指定承諾所需完成的事

  2.設置承諾是否實現的標準

下面咱們來定義一個承諾:

  1.承諾的內容:「獲取data.php的數據」,

  2.承諾是否實現的評判是:是否獲取data.php的數據 」

這裏咱們會用到jQuery.ajax()方法,這會讓咱們的代碼顯得簡單精煉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var  http = {
     get:  function (url) {
         var  promise =  new  Promise( function (resolve, reject) {
             $.ajax({
                 url: url,
                 method:  'get' ,
                 success:  function (data) {
                     resolve(data);
                 },
                 error:  function (xhr, statusText) {
                     reject(statusText);
                 }
             });
         });
         return  promise;
     }
};
http.get( 'data.php' ).then( function (data) {
     document.write(data);
},  function (err) {
     document.write(err);
});

  這裏是獲取的data值

1
2
3
/* data.php文件 */
<?php
echo  '{"name":"Tom","age":"22"}' ;

  在http請求中,咱們定義了一個get方法,在get方法中,咱們定義了一個promise的對象,而不是直接直接使用ajax獲取到咱們想要的數據,在這個get方法,咱們最後獲得的是一個promise對象,對於這種須要等待的操做,咱們採用promise去處理,返回給主線程的是一個promise對象,而不是一個最終的數據,這是延遲程序給主程序的一個承諾,主線程能夠根據經過返回的promise對象獲取數據或者處理錯誤。這使得異步處理變得優雅而簡單。

  在jQuery.ajax()中,咱們採用了兩個方法來判斷是否實現了咱們的承諾,它們分別是resove和reject方法,若是若是jQuery.ajax()執行了success,而且返回的data中有數據,那麼咱們就斷定這個承諾已經實現了(fulfilled),則調用resolve方法。若是jQuery.ajax()執行了error,那麼咱們就斷定這個承諾被拒絕了(rejected),則調用reject方法。

那resove和reject這兩個方法分別執行了哪些操做呢?這個咱們就須要從Promise這個構造函數自己的結構提及。Promise這個構造函數結構大概是下面這樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 用於描述思惟的代碼 */
function  Promise(executor) {
     // 共有三種狀態:pending(準備)、fulfilled(完成)、rejected(拒絕)
     this .PromiseStatus =  'pending' ;
     // 用於存儲返回的數據
     this .PromiseValue;
     // 完成
     var  resolve =  function (reson) {};
     // 拒絕
     var  reject =  function (reson) {};
     ...
     // 開始執行承諾
     executor(resolve, reject);
}
Promise.prototype.then =  function () {};
Promise.prototype.chain =  function () {};
Promise.prototype. catch  function () {};
...

  

PromiseStatus:用於記錄Promise對象的三種狀態,這三中狀態分別是:
pending:待定狀態,Promise對象剛被初始化的狀態
fulfilled:完成狀態,承諾被完成了的狀態
rejected:拒絕狀態,承諾完成失敗的狀態
Promise的初始狀態是pending。隨後會更具承諾完成的狀況更改PromiseStatus的值。

PromiseStatus:用於記錄返回的數據或者錯誤。當承諾完成時,會把返回的數據賦給PromiseStatus。若是承諾執行失敗了,那麼失敗的緣由也會賦給此變量。

resolve()和reject():Promise構造函數中有兩個閉包的函數resolve()和reject()。在new一個新的Promise的時候會傳遞一件你須要作的事情(executor)。這個executor是一個函數,在Promise的構造函數中它會被傳入兩個參數,這兩個參數即咱們的兩個閉包的函數resolve()和reject(),以便你在executor中斷定是否完成了你的承諾。

executor(): executor()函數中執行的代碼就是子程序須要完成事。在executor()函數內若是調用了resolve(),resolve()則會把Promise對象的狀態PromiseStatus修改成fulfilled,把resolve(value)中的value值賦給Promise對象的PromiseValue。而後再依次執行由then()方法構成的回調鏈中的回調函數。一樣,在executor()中調用reject()的過程也是相似的。調用過程以下:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
/* 用於描述思惟的代碼 */
executor(resolve, reject) {
     ...
     resolve(value);
     ...
}
...
resolve(value) {
     PromiseStatus =  'fulfilled' ;
     PromiseValue = value;
     ...
     // 接着調用回調鏈中的回調函數
}

  

then(onFulfilled, onRejected):這個方法其實是把onFulfilled()函數和onRejected()函數添加到Promise對象的回調鏈中。回調鏈就像一個由函數組構成的隊列,每一組函數都是由至少一個函數構成(onFulfilled() 或者 onRejected() 或者 onFulfilled() 和 onRejected())。當resolve()或者reject()方法執行的時候,回調鏈中的回調函數會根據PromiseStatus的狀態狀況而被依次調用。

onFulfilled(value)和onRejected(reason):參數value和reason的實參都是PromiseValue。這裏有一點值得注意,若是onFulfilled(value)和onRejected(reason)這兩個回調函數中return返回值不是一個Promise的對象,那麼這個返回值會被賦給PromiseValue,並在下一個then()的onFulfilled(value)和onRejected(reason)中作爲實參使用。但若是這個返回值是一個Promise的對象,那麼剩下的由then()構造的回調鏈會轉交給新的Promise對象並完成調用。

有這樣一個問題,若是在第一個then()中執行了onRejected(reason)回調函數,而且沒有return任何值的時候,那麼下一個then()中將會調用onFulfilled(value)方法,而不是onRejected(reason)。由於在執行上一個then()的onRejected(reason)回調函數的時候並無出現錯誤或異常,因此PromiseStatus的狀態就被更改成fulfilled了。爲了不這個問題,咱們能夠在onRejected(reson)中返回一個Promise對象並reject()。代碼以下,咱們要去訪問一個並不存在的文件solve.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var  http = {
     get:  function (url) {
         var  promise =  new  Promise( function (resolve, reject) {
             $.ajax({
                 url: url,
                 method:  'get' ,
                 success:  function (data) {
                     resolve(data);
                 },
                 error:  function (xhr, statusText) {
                     reject(statusText);
                 }
             });
         });
         return  promise;
     }
};
http.get( 'solve.php' ).then( function (data) {
     return  data;
},  function (err) {
     return  Promise.reject( 'Sorry, file not Found.' );
}).then( function (data) {
     document.write(data);
},  function (err) {
     document.write(err);
});

  Promise.reject()方法會返回一個被reject()的Promise對象,所以使得咱們能夠繼續走下一個then()中的onRejected(reason)方法。

相關文章
相關標籤/搜索