Promise總結

2019第三發javascript

說明

Promise是一個構造函數,本身身上有call、resolve、reject,原型上有then、catch等方法。 Promise 對象有如下兩個特色。html

  1. 對象的狀態不受外界影響。有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和 Rejected(已失敗)。
  2. 一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise 對象的狀態改變,只有兩種可能:從 Pending 變爲 Resolved 和從 Pending 變爲 Rejected。

這與事件(Event)徹底不一樣,事件的特色是,若是你錯過了它,再去監聽,是得不到結果的。java

開始

初步理解

var promise = new Promise(function(resolve, reject) {
    setTimeout(function(){
       console.log('完成')
       resolve('隨便什麼東西')
    }, 2000)
})
複製代碼

相似這樣,Promise的構造函數接受一個參數:函數。而且會傳入兩個參數resolve、reject,用來表示成功或者失敗。git

通常狀況會把promise放在一個函數中,當函數調用時候纔會執行promise的操做。es6

function runAsync(){
    var p = new Promise(function(resolve, reject){
        //作一些異步操做
        setTimeout(function(){
            console.log('執行完成');
            resolve('隨便什麼數據');
        }, 2000);
    });
    return p;            
}
runAsync().then(function(data){
    console.log(data);
    //後面能夠用傳過來的數據作些其餘操做
    //......
});
複製代碼

表面上看Promise只是簡化層層的回調寫法,實質上,Promise的精髓是狀態github

鏈式操做的用法

function runAsync1(){
    var p = new Promise(function(resolve, reject){
        //作一些異步操做
        setTimeout(function(){
            console.log('異步任務1執行完成');
            resolve('隨便什麼數據1');
        }, 1000);
    });
    return p;            
}
function runAsync2(){
    var p = new Promise(function(resolve, reject){
        //作一些異步操做
        setTimeout(function(){
            console.log('異步任務2執行完成');
            resolve('隨便什麼數據2');
        }, 2000);
    });
    return p;            
}
function runAsync3(){
    var p = new Promise(function(resolve, reject){
        //作一些異步操做
        setTimeout(function(){
            console.log('異步任務3執行完成');
            resolve('隨便什麼數據3');
        }, 2000);
    });
    return p;            
}
複製代碼
runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});
複製代碼

結果

runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return '直接返回數據';  //這裏直接返回數據
})
.then(function(data){
    console.log(data);
});
複製代碼

結果

reject的用法

reject的做用就是把Promise的狀態置爲rejected,這樣咱們在then中就能捕捉到,而後執行「失敗」狀況的回調。promise

then方法能夠接受兩個參數,第一個對應resolve的回調,第二個對應reject的回調。dom

var promise = new Promise((resolve, reject) => {
    reject('失敗')
})
promise.then((data) =>{
    console.log('success:' + data)
},(reason) => {
    console.log('error:' + reason);
})
複製代碼

catch的用法

Promise除了then還有catch方法,他和then的第二個參數同樣,用來指定reject的回調。可是他還有一個做用:當在執行resolve的回調時候,若是出現異常那麼js不會卡死,而是會進入到catch方法中。異步

當catch上面有處理reject的函數時候,會一級一級的處理,而不是直接跳到catch中。async

function getNumber(){
    var p = new Promise(function(resolve, reject){
        //作一些異步操做
        setTimeout(function(){
            var num = Math.ceil(Math.random()*10); //生成1-10的隨機數
            if(num<=5){
                resolve(num);
            }
            else{
                reject('數字太大了');
            }
        }, 2000);
    });
    return p;            
}
getNumber()
.then(function(data){
    console.log(data);
    console.log(somedata); //此處的somedata未定義
}).then((data) =>{
    console.log('success:' + data)
},(reason) => {
    console.log('error:' + reason);
})
.catch(function(reason){
    console.error(reason);
});
複製代碼

all的用法

Promise的all方法提供了並行執行異步操做的能力,而且在全部異步操做執行完後才執行回調。

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});
複製代碼

結果

race的用法

all => 誰跑的慢,以誰爲準執行回調

race => 誰跑的快,以誰爲準執行回調

Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});
複製代碼

結果
在then裏面的回調開始執行時,runAsync2()和runAsync3()並無中止,仍舊再執行。因而再過1秒後,輸出了他們結束的標誌。

race的應用場景

function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}
//延時函數,用於給請求計時
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('圖片請求超時');
        }, 5000);
    });
    return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});
複製代碼

結果

finally

finally方法用於指定無論 Promise 對象最後狀態如何,都會執行的操做。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
複製代碼

finally方法的回調函數不接受任何參數,這意味着沒有辦法知道,前面的 Promise 狀態究竟是fulfilled仍是rejected。這代表,finally方法裏面的操做,應該是與狀態無關的,不依賴於 Promise 的執行結果。

finally本質上是then方法的特例。

Promise的異常捕獲方式

在Promise的構造體內進行錯誤處理

var promise=new Promise(function(resolve,reject){
   try {
      throw new Error('test');
   }catch(e){
      reject(e)
   }
})
複製代碼

經過Promise.prototype.catch來進行錯誤處理

var promise=new Promise(function(resolve,reject){
   reject(new Error('test'));
})
promise.catch(function(e){
 //something to deal with the error
 console.log(e)
})
複製代碼

catch方面裏面還能夠再拋錯誤,這個錯誤會被後面的catch捕獲

var promise=new Promise(function(resolve,reject){
  reject(new Error('test1'))
})
promise.catch(function(e){
  console.log(e);
  throw new Error('test2')
}).catch(function(e){
  console.log(e)
})
  
  // Error : test1
  // Error : test2
複製代碼

Promise.all中的異常捕獲

若是組成Promise.all的promise有本身的錯誤捕獲方法,那麼Promise.all中的catch就不能捕獲該錯誤。

var p1=new Promise(function(resolve,reject){
  reject(new Error('test1'))
}).catch(function(e){
  console.log("由p1自身捕獲",e);
})
var p2=new Promise(function(resolve,reject){
  resolve();
})
var p=Promise.all([p1,p2]);
p.then(function(){

}).catch(function(e){
  //在此處捕獲不到p1中的error
  console.log(e)
})
//由p1自身捕獲 Error: test1
複製代碼

在promise中沒法被捕獲的錯誤

在promise實例resolve以後,錯誤沒法被捕獲。

var promise=new Promise(function(resolve,reject){
   resolve();
   throw new Error('test');//該錯誤沒法被捕獲
})
promise.then(function(){
  //
}).then(function(e){
  console.log(e)
})
複製代碼

支持

支持
支持

常見問題

參考

  1. ES6 Promise 用法講解
  2. 總結一下ES6/ES7中promise、generator和async/await中的異常捕獲方法
  3. Promise 對象 - ECMAScript6入門

總結

相關文章
相關標籤/搜索