ES6_Promise 對象 阮一鋒


Promise的含義

promise是異步編程的一種解決方法,比傳統的回調函數和事件更合理更強大
。他由社區最早提出和實現,ES6將其寫進語言標准,統一了用法,原生提供了promise對象。
所謂promise,簡單說是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果,從語法上說,promise是一個對象,從它可以獲取異步操作的消息,promise提供了統一的API,各種異步操作都可以用同樣的方法進行處理。

 

promise對象的特點

(1)對象的狀態不受外界影響,promise對象代表一個異步操作,有三種狀態,pending(進行中)、fulfilled(已成功)、rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,這也是promise這個名字的由來“承若”;
(2)一旦狀態改變就不會再變,任何時候都可以得到這個結果,promise對象的狀態改變,只有兩種可能:從pending變為fulfilled,從pending變為rejected。這時就稱為resolved(已定型)。如果改變已經發生了,你再對promise對象添加回調函數,也會立即得到這個結果,這與事件(event)完全不同,事件的特點是:如果你錯過了它,再去監聽是得不到結果的。

有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,是的控制異步操作更加容易。

Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)

一 。用法:

promise 對象是一個構造函數,用來生成promise實例;

創建一個promise對象實例:

var promise =new Promise(function(resolve,reject){
      //some  code 
   if(//異步操作成功) {
   resolve(value);
     
} else{
   reject(error); 
}
        
});

Promise構造函數接收一個函數作為參數,該函數的兩個參數分別是resolvereject,他們是兩個函數,由Javascript引擎提供,不用自己部署。

resolve函數的作用是,將promise對象的狀態從“pending”變為‘’resolved‘’,在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;

reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。

promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數

promise.then(
    function(value){
     //success
}  ,
   function(error){
     //failure
} );

then方法可以接受連個回調函數作為參數,第一個回調函數是promise對象的狀態變為resolved時調用,第二個回調函數是promise對象的狀態變為rejected時調用,其中,第二個函數是可選的,不一定要提供,這兩個函數都接受promise對象傳出的值作為參數;


promise對象的簡單例子

<script>
     function timeOut(ms){
          return new Promise(function(resolve,reject){
                return setTimeout(resolve,ms,'done');
            })
        }
     timeOut(3000).then(function(value){
     console.log(value);
        })
 </script>

timeOut方法返回一個promise實例,表示一段時間以后才會發生的結果,過了指定的時間(ms)以后,promise實例的狀態變為resolved,就會觸發then方法綁定的回調函數

Promise新建后會立即執行

 let promise =new Promise(function(resolve,reject){
                console.log('Promise');
                resolve();
            });
            promise.then(function(){
                console.log('resolved');
            });
            console.log('Hi!');

//Promise 
// Hi! 
// resolved

Promise 新建后立即執行,所以首先輸出的是Promise。然后,then方法指定的回調函數,將在當前腳本所有同步任務執行完才會執行,所以resolved最后輸出。

  異步加載圖片的例子

<script>
        function loadImageAsync (url) {
             return new Promise( function( resolve, reject){
                  var image = new Image(); 
                  image .onoad =function(){
                       resolve(image); }; 
                    image. = function () { 
                        reject(new Error("could not load image at "+ url) ); };
                         image.src =url;
                    }); }
                    
             loadImageAsync(url).then( function (value) { 
                 console.log(value);
                  })
    </script>

 

使用Promise包裝了一個圖片加載的異步操作。如果加載成功,就調用resolve方法,否則就調用reject方法。

promise對象實現ajax操作的例子

var getJSON = function (url) {
var promise = new Promise( function(resolve,reject ) {
  var XHR = new XMLHttpRequest();
  XHR.open("GET",url);
  XHR.onreadystatechange = function () {
   if (this.readyState !==4) {return;}
    if(this.status == 200) {
    resolve(this.response); } else{
    reject(new Error(this.statusText) );
      }
    };
   XHR.responseType = "json";
   XHR.setRequestHeader("Accept","application/json");
  XHR.send();
});

return promise;
};
getJSON("posts.json").then(function(json){
console.log("Contents : "+json );
}, function(error) {
console.log("出錯了", error);
}) ;

 

getJSON是對XMLHTTPRequest對象的封裝,用於發出一個針對JSON數據的HTTP請求,並且返回一個promise對象,需要注意的是,在getJSON內部,resolve函數和reject函數調用時,都帶有參數;
如果調用resolve函數和reject函數時帶有參數,那么他們的參數會被傳遞給回調函數,reject函數的參數通常是Error對象的實例,表示拋出的錯誤,resolve函數的參數除了正常的值以外,還可以是另一個promise實例;
  

p1和p2都是 Promise 的實例,但是p2的resolve方法將p1作為參數,即一個異步操作的結果是返回另一個異步操作。
這時p1的狀態就會傳遞給p2,也就是說,p1的狀態決定了p2的狀態。如果p1的狀態是pending,那么p2的回調函數就會等待p1的狀態改變;如果p1的狀態已經是resolved或者rejected,那么p2的回調函數將會立刻執行。


注意,調用resolve或reject並不會終結 Promise 的參數函數的執行。

調用resolve(1)以后,后面的console.log(2)還是會執行,並且會首先打印出來。這是因為立即 resolved 的 Promise 是在本輪事件循環的末尾執行,總是晚於本輪循環的同步任務。

一般來說,調用resolve或reject以后,Promise 的使命就完成了,后繼操作應該放到then方法里面,而不應該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。

Promise.prototype.then()

promise實例具有then方法,也就是說,then方法定義在原型對象Promise.prototype上的。它的作用是為Promise實例添加狀態改變時的回調函數。前面說過,then方法的第一個參數是resolved狀態的回調函數,第二個參數是rejected狀態的回調函數。

  then方法返回的是一個新的Promise實例(不是原來那個Promise實例),因此可以采用鏈式寫法,即then方法后面再調用另一個then方法

依次指定了兩個回調函數,第一個回到函數完成以后會將返回結果作為參數,傳入第二個回調函數。
采用鏈式的then,可以指定一組按照次序調用的回調函數。這時前一個回調函數,有可能返回的還是一個promise對象(即有異步操作),這時后一個回調函數,就會等待該promise對象的狀態發生變化,才會被調用。

 

上面第一個then方法指定的回調函數,返回的是另一個promise對象,這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。如果變為resolved,就調用funA,如果狀態變為rejected,就調用funB。改為箭頭函數,代碼更簡潔:

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM