C-JavaScript-03:使用ES6中的新特性Promise解決回調地獄問題

不想了解過程,請直接劃到最後.看最終效果

更多內容歡迎訪問個人博客:林除夕javascript

什麼是回調地獄

通俗的說就是回調函數嵌套回調函數的問題,以下java

// 聲明一個函數
function foo(data, callback) {
    data++;
    callback(data);
}

// 回調地獄
foo(1, function(data) {
    foo(data, function(data) {
        foo(data, function(data){
            foo(data, function(data){
                foo(data, function(data){
                    foo(data, function(data){
                        console.log(data);// 7
                    })
                })
            })
        })
    });
});

怎麼樣是否是很刺激,稍微複雜一點,保證你看到頭暈眼花。ajax

解決回調地獄的基本思路


將這種嵌套式的調用改造爲串聯式,那麼下面咱們就來看看怎麼解決.json

解決辦法===>Promise


1.什麼是Promise

  1. 是一個構造函數:咱們經過輸出window對象獲得相關信息
  2. 其中的關鍵方法網絡

    • then: 用來指定接下來要執行的函數(成功的回調函數,失敗的回調函數)
    • resolve: 成功以後的回調函數 ===> 必需要傳的
    • reject: 失敗的回調函數 ===> 不是必須傳的
  3. 表示一個異步操做: 當實例被建立時就表示一個具體異步操做若是不傳入執行函數,那麼它只是在形式上是異步操做,可是沒有任何的異步實操以下異步

    // 建立一個形式上的異步操做 ===> 沒有任何具體的異步操做(例如ajax,jsonp等),咱們知道它是異步操做可是不知道它究竟在操做什麼
    var p = new Promise();
    
    // 建立一個實際的異步操做
    var p = new Promise(function(){
        // 在這裏執行一個異步操做,例如:ajax請求
    })
  4. 實例被建立時,傳入的函數會被當即執行: 因此通常都先將實例化過程封裝在函數中,這樣才能在須要的時候再執行

2.如何使用

  1. 經過.then指定回調函數(包括成功和失敗),以下:函數

    // 爲了防止咱們的異步操做函數在Promise實例化過程當中被執行,將其封裝在一個函數中,在對應的時機去使用它
    function sendAjax() {
        // 建立並返回一個包含實際的異步操做的Promise對象
        return new Promise(function(resolve,reject) {
            // 在這裏執行一個異步操做,例如:ajax請求
    
            if('ajax請求出現錯誤') return reject('錯誤內容')
            resolve('成功以後須要用到的數據或內容')
        });
    }
    
    // 接收實例對象
    var p = sendAjax()
    
    // 經過.then方法指定成功和失敗的回調
    p.then(function(data){
        // 默認第一個是成功的回調
    }, function(err){
        // 默認第二個是失敗的回調
    })
  2. 同執行過程以下: 在異步操做的等待時間內完成後續的處理函數的註冊(由於異步操做受網絡和數據大小的限制通常時間都較長,然後續註冊執行函數由於都是內存內直接操做且數據量很小注冊時間幾乎能夠忽略不計)jsonp

    st=>start: 開始
    e=>end: 結束
    op1=>operation: 調用函數實例化對象
    op2=>operation: 發起異步操做請求
    op3=>operation: 註冊回調函數p.then
    op4=>operation: 完成異步請求
    op5=>operation: 調用回調函數
    op6=>operation: 異步請求是否完成
    cont=>condition: yes or no?
    st->op1->op2->op6->cont
    cont(no)->op3->op5
    cont(yes)->op5->e

3.最終效果

注意:code

在調用.then的時候,成功的回調(resolve)是必須的,失敗的回調(reject)能夠不傳遞
// 爲了防止咱們的異步操做函數在Promise實例化過程當中的執行,將其封裝在一個函數中
function sendAjax(data) {
    // 建立並返回一個包含實際的異步操做的Promise對象
    return new Promise(function(resolve,reject) {
        // 在這裏執行一個異步操做,例如:ajax請求

        if('ajax請求出現錯誤') return reject('錯誤內容')
        resolve('成功以後須要用到的數據或內容')
    });
}

// 接收實例對象
var p = sendAjax(data)
// 經過.then方法指定成功和失敗的回調
p.then(function(data){
    // 默認第一個是成功的回調
}, function(err){
    // 默認第二個是失敗的回調
})

// ========================
// 串聯解決回調地獄問題
sendAjax(data)
    .then(function(newData1){
    // newData就是異步操做獲得的數據或內容
    // 這裏用來放成功以後如何處理

    // 數據處理完成後若是還須要執行嵌套的相似操做
    return sendAjax(newData2)
})
    .then(function(newData3){
    // newData就是異步操做獲得的數據或內容
    // 這裏用來放成功以後如何處理

    // 數據處理完成後若是還須要執行嵌套的相似操做
    return sendAjax(newData4)
})
    .then....
    .then(function(result){
        // 結束數據嵌套處理,輸出數據
        console.log(result)
    })

4.捕獲異常或錯誤

有兩種狀況,一種會阻止後續執行,一種不會對象

  1. 不阻止後續執行的捕獲,提供一個失敗的回調函數
sendAjax(data)
    .then(function(newData1){
        // newData就是異步操做獲得的數據或內容
        // 這裏用來放成功以後如何處理

        // 數據處理完成後若是還須要執行嵌套的相似操做
        return sendAjax(newData2)
    },function(err){
        // 在這裏執行一個處理失敗信息的操做
    
        // 處理完成後返回下一個要處理的對象,這樣就不會阻止後續操做
        return sendAjax(newData2)
    })
    .then(function(newData3){
        // newData就是異步操做獲得的數據或內容
        // 這裏用來放成功以後如何處理

        // 數據處理完成後若是還須要執行嵌套的相似操做
        return sendAjax(newData4)
    })
  1. 阻止後續執行的捕獲
sendAjax(data)
    .then(function(newData1){
        // newData就是異步操做獲得的數據或內容
        // 這裏用來放成功以後如何處理

        // 數據處理完成後若是還須要執行嵌套的相似操做
        return sendAjax(newData2)
    })
    .then(function(newData3){
        ...
    })
    .catch(function(err){
        // 輸出錯誤信息
        // 這種方式捕獲異常和錯誤,只要前面任何一個.then出現問題都會終止整個執行鏈,而後拋出異常
    })
相關文章
相關標籤/搜索