ES6中Promise 承諾對象封裝異步操做解析

Promise

是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件)更合理和更強大。它由社區最先
出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。node

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。
有了Promise對象,就能夠將異步操做以同步操做的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操做更加容易ajax

異步的解決方案:

  • 1)傳統ajax編程

    是一種異步的JavaScript的請求,可以在不影響當前進程的狀況下和後臺進行交互.
               1.發起請求
                   請求的返回時間難以肯定,影響因素比較多,好比網絡延遲
               2.監聽(成功,失敗)
                   經過判斷狀態碼來決定執行那個回調函數
                   200 ok
                   404 not found
                   500 後臺代碼異常
                   403 無權訪問
                   304 文檔內容沒有發生改變
               3.調用回調函數
                   完成請求後的處理
    
    
    
             $.getJSON('http://120.78.164.247:8080/grade',function(data){
               alert(data)
               });
               alert('end');
               //先執行end 在彈出data

出現的問題:在回調函數中嵌套若是比較多,就很容易出問題json

  • 2)promise數組

    承諾
       存在三種狀態:
           1.未知狀態,
           2.成功狀態,resolve() 未知狀態---》成功狀態
           3.失敗狀態,reject()    未知狀態---》失敗狀態
       ajax中使用最多
       
       
       let promise = new Promise((resolve,reject)=>{
       $.ajaxSetup({
           error:function(){reject()};    //失敗
          });
           $.get('',function(data){
           resolve(data);    //成功
          });
       promise.then(()={}).catch(()=>{});

在個人理解中promise是對ajax的一種封裝,上述代碼中,使用的是用JQuery封裝的ajax代碼分紅了兩部分。promise

對異步操做Ajax的封裝

  • 1.先來看看咱們本身封裝一個Ajax
let fetch = (method,url,successHandler,errorHandler)=>{
        let xhr = new XMLHttpRequest();
        xhr.open(method,url);
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept','application/json');//設置頭部信息
        
        xhr.onreadystatechange = function(){
            if(this.readyState == 4){
                if(this.status == 200){
                    successHandler(this.response)
                }else{
                    errorHandler(this.response);
                };
            }
        };
        xhr.send();
    
    }

須要注意的是由於原生代碼中須要http協議,因此這個代碼在node中是沒法使用的,服務器

  • 2.下面來看看使用promise來封裝網絡

    簡單的思路:app

    let promise = new Promise((resolve,reject)=>{
       
           setTimeout(function(){//模擬異步請求
               if (Math.round(Math.random()*10)>5) {
                           resolve('success');//成功
                       }else{
                           reject('erro');//失敗
                       }
       
           },3000);
       
       });
       
       promise.then((data)=>{
           console.log(data);
       }).catch((erro)=>{
           console.log(erro);
       });

    咱們來看看promise如何封裝Ajaxdom

    let fetch = (method,url)=>{
           return new Promise((resolve,reject)=>{
               let xhr = new XMLHttpRequest();//聲明一個請求
               xhr.open(method,url);
               xhr.responseType = 'json';
               xhr.setRequestHeader('Accept','application/json');
               xhr.onreadystatechange = function(){
                   if(this.readyState == 4){//判斷狀態
                   if(this.status == 200){
                       resolve(this.response)
                   }else{
                       reject(this.response);
                   };
               };
               };
                   xhr.send();//發送請求
           });
       };
       fetch('get','http://120.78.164.247:8080/grade/findAll').then(({code,msg,extend})=>{
           console.log(code);
           console.log(msg);
           console.log(extend);
       }).catch(()=>{});//調用本身封裝的fetch

Promise經常使用方法

接着,咱們來看看Promise中的一些基本用法

  • 1.Promise.prototype.then()

    .then(function(){//success},functions(){//error});

then方法是定義在原型對象Promise.prototype上的,也就是說,Promise 實例具備then方法。它的做用是爲 Promise 實例添加狀態改變時的回調函數。then方法的第一個參數是Resolved狀態的回調函數,第二個參數(可選)是Rejected狀態的回調函數。then方法返回的是一個新的Promise實例注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法,即then方法後面再調用另外一個then方法。若是使用兩個then方法,第一個回調函數完成之後,會將返回結果做爲參數,傳入第二個回調函數。

getJSON("/post/1.json").then( 
    post => getJSON(post.commentURL)
 ).then( 
    comments => console.log("Resolved: ", comments), 
    err => console.log("Rejected: ", err) 
);

上面代碼中,第一個then方法指定的回調函數,返回的是另外一個Promise對象。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。若是變爲resolved,就調用funcA,若是狀態變爲rejected,就調用funcB。

  • 2.Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數,通常來講,不要在then方法裏面定義Reject狀態的回調函數(即then的第二個參數)老是使用catch方法

var promise = new Promise(function(resolve, reject) { 
    reject(new Error('test')); 
});
 promise.catch(function(error) { 
    console.log(error);
 });

Promise 對象的錯誤具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch語句捕獲。

  • 3.Promise.all()

Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。

var p = Promise.all([p1, p2, p3]);

上面代碼中,Promise.all方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例,p的狀態由p一、p二、p3決定,分紅兩種狀況。
只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

  • 4.Promise.race()

Promise.race方法一樣是將多個Promise實例,包裝成一個新的Promise實例。下面代碼中,只要p一、p二、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。

var p = Promise.race([p1, p2, p3]);

上面代碼中,Promise.all方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例,p的狀態由p一、p二、p3決定,分紅兩種狀況。
只有p一、p二、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

  • 5.Promise.resolve()

方法將現有對象轉爲Promise對象,例如:

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

根據參數的不一樣,方法的返回值也會發生變化:

1.參數是一個Promise實例
Promise.resolve將不作任何修改、原封不動地返回這個實例。
2.參數是一個thenable對象
thenable對象指的是具備then方法的對象,Promise.resolve方法會將這個對象轉爲Promise對象,而後就當即執行thenable對象的then方法。
3.參數不是具備then方法的對象,或根本就不是對象
若是參數是一個原始值,或者是一個不具備then方法的對象,則Promise.resolve方法返回一個新的Promise對象,狀態爲Resolved。
4.不帶有任何參數
直接返回一個Resolved狀態的Promise對象。須要注意的是,當即resolve的Promise對象,是在本輪「事件循環」(event loop)的結束時,而不是在下一輪「事件循環」的開始時。
  • 6.Promise. reject()

Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態爲rejected 。

var p = Promise.reject('出錯了'); 
// 等同於 
var p = new Promise((resolve, reject) => reject('出錯了')) ;
  • 7.finally()

finally方法用於指定無論Promise對象最後狀態如何,都會執行的操做。它接受一個普通的回調函數做爲參數,該函數無論怎樣都必須執行。
下面是一個例子,服務器使用Promise處理請求,而後使用finally方法關掉服務器

server.listen(0) .then(function () {
     // run test
 }) .finally(server.stop);    //關掉服務器

使用總結

Promise對象的使用大體分爲以下幾個步驟:

1. 構建承諾對象
    let promise = new Promise((resolve,reject)=>{
      // resolve()    未知->成功
      // reject()     未知->失敗
    });
 2. 執行
    promise.then(()=>{
      //成功後的回調
    }).catch(()=>{
      //失敗後的回調
    });

 3. 企業級應用
相關文章
相關標籤/搜索