1. 程式人生 > >JS - Promise使用詳解1(基本概念、使用優點)

JS - Promise使用詳解1(基本概念、使用優點)

一、promises相關概念

promises 的概念是由 CommonJS 小組的成員在 Promises/A 規範中提出來的。

 

1,then()方法介紹

根據 Promise/A 規範,promise 是一個物件,只需要 then 這一個方法。then 方法帶有如下三個引數:

  • 成功回撥
  • 失敗回撥
  • 前進回撥(規範沒有要求包括前進回撥的實現,但是很多都實現了)。

一個全新的 promise 物件從每個 then 的呼叫中返回。

 

2,Promise物件狀態

Promise 物件代表一個非同步操作,其不受外界影響,有三種狀態:

  • Pending(進行中、未完成的)
  • Resolved(已完成,又稱 Fulfilled)
  • Rejected(已失敗)。

(1)promise 從未完成的狀態開始,如果成功它將會是完成態,如果失敗將會是失敗態。

(2)當一個 promise 移動到完成態,所有註冊到它的成功回撥將被呼叫,而且會將成功的結果值傳給它。另外,任何註冊到 promise 的成功回撥,將會在它已經完成以後立即被呼叫。

(3)同樣的,當一個 promise 移動到失敗態的時候,它呼叫的是失敗回撥而不是成功回撥。

(4)對包含前進特性的實現來說,promise 在它離開未完成狀態以前的任何時刻,都可以更新它的 progress。當 progress 被更新,所有的前進回撥(progress callbacks)會被傳遞以 progress 的值,並被立即呼叫。前進回撥被以不同於成功和失敗回撥的方式處理;如果你在一個 progress 更新已經發生以後註冊了一個前進回撥,新的前進回撥只會在它被註冊以後被已更新的 progress 呼叫。

(5)注意:只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

 

3,Promise/A規範圖解

原文:JS - Promise使用詳解1(基本概念、使用優點)

 

4,目前支援Promises/A規範的庫

  • Q:可以在NodeJS 以及瀏覽器上工作,與jQuery相容,可以通過訊息傳遞遠端物件。
  • RSVP.js:一個輕量級的庫,它提供了組織非同步程式碼的工具。
  • when.js:體積小巧,使用方便。
  • NodeJS的Promise
  • jQuery 1.5:據說是基於“CommonJS Promises/A”規範
  • WinJS / Windows 8 / Metro

 

二、使用promises的優勢

1,解決回撥地獄(Callback Hell)問題

(1)有時我們要進行一些相互間有依賴關係的非同步操作,比如有多個請求,後一個的請求需要上一次請求的返回結果。過去常規做法只能 callback 層層巢狀,但巢狀層數過多的話就會有 callback hell 問題。比如下面程式碼,可讀性和維護性都很差的。

1

2

3

4

5

6

7

8

9

10

11

12

firstAsync(function(data){

    //處理得到的 data 資料

    //....

    secondAsync(function(data2){

        //處理得到的 data2 資料

        //....

        thirdAsync(function(data3){

              //處理得到的 data3 資料

              //....

        });

    });

});

 

(2)如果使用 promises 的話,程式碼就會變得扁平且更可讀了。前面提到 then 返回了一個 promise,因此我們可以將 then 的呼叫不停地串連起來。其中 then 返回的 promise 裝載了由呼叫返回的值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

firstAsync()

.then(function(data){

    //處理得到的 data 資料

    //....

    return secondAsync();

})

.then(function(data2){

    //處理得到的 data2 資料

    //....

    return thirdAsync();

})

.then(function(data3){

    //處理得到的 data3 資料

    //....

});

 

2,更好地進行錯誤捕獲 

多重巢狀 callback 除了會造成上面講的程式碼縮排問題,更可怕的是可能會造成無法捕獲異常或異常捕獲不可控。
(1)比如下面程式碼我們使用 setTimeout 模擬非同步操作,在其中丟擲了個異常。但由於非同步回撥中,回撥函式的執行棧與原函式分離開,導致外部無法抓住異常。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

function fetch(callback) {

    setTimeout(() => {

        throw Error('請求失敗')

    }, 2000)

}

 

try {

    fetch(() => {

        console.log('請求處理'// 永遠不會執行

    })

catch (error) {

    console.log('觸發異常', error) // 永遠不會執行

}

 

// 程式崩潰

// Uncaught Error: 請求失敗

 

(2)如果使用 promises 的話,通過 reject 方法把 Promise 的狀態置為 rejected,這樣我們在 then 中就能捕捉到,然後執行“失敗”情況的回撥。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

function fetch(callback) {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

             reject('請求失敗');

        }, 2000)

    })

}

 

 

fetch()

.then(

    function(data){

        console.log('請求處理');

        console.log(data);

    },

    function(reason, data){

        console.log('觸發異常');

        console.log(reason);

    }

);


當然我們在 catch 方法中處理 reject 回撥也是可以的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

function fetch(callback) {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

             reject('請求失敗');

        }, 2000)

    })

}

 

 

fetch()

.then(

    function(data){

        console.log('請求處理');

        console.log(data);

    }

)

.catch(function(reason){

    console.log('觸發異常');

    console.log(reason);

});

原文連結:http://www.hangge.com/blog/cache/detail_1635.html