Promise的理解與隨手實例

我們 學習一個新的特性時,我習慣先了解他是什麼, 有什麼用

在 w3c中 可知 Promise 是 抽象異步處理對象以及對其進行各種操作的組件 . 他 多用於 處理回調地獄 . 什麼是回調地獄呢? 即 嵌套多個回調 如果 有多個回調互相嵌套 則 會難以調試與 理解 增大代碼維護的難度與可讀性

使用 promise 就能解決這個問題 , promise 可以是一個佔位符,表示異步操作的執行結果, 函數可以返回一個promise 而不 是 傳遞一個回調

promise 都會有一個 短暫的生命週期

有兩種狀態

初始的掛起未決狀態 --> 異步未結束

已決的狀態 ---> 異步操作結束

處於 已決轉態 會有兩種情況

1  已經成功完成的異步操作

2 可能是一個錯誤或者其他的原因導致了 異步的操作沒成功

此時 promise中有個 [ [PromiseState]] 屬性 會被設置 爲 pending fulfilled 或者 rejected , 以反映 promise 的狀態處於 哪一步 . 但這個屬性 並不在 promise 對象上面 暴露. 因此 無法 判斷 他處於那種狀態

但此時其 提供了

then() 方法 

他在所有的promise 上都存在. 並且接受兩個參數  .

  	第一個 參數 是promise 被完成時 調用的 函數  , 異步操作的結果數據  
  		都會傳入 完成函數

  	第二個函數 則是 promise 被拒絕的時調用的函數, 也會將失敗的參數數據   

	這兩個參數是可選的  可以自由的監聽 完成 和失敗的處理函數

catch 方法 

Promise有catch()方法,等同於只傳遞拒絕處理函數給then()方法:

用處
比如 Vue 發起axios 的請求時 正常來說異步 返回的是 一個 回調函數. 但此時 使用 promise 直接返回一個 axios.get或者 axios.post 讓這個 promise 對象 (axios是promise對象 )自己 進行 成功 ( .then() ) 之後的 處理 或者失敗(.catch() ) 的提示

他人總結:
Promise 具有三種狀態:掛起、已完成、已拒絕。一個 Promise 起始於掛起態,並在成功時轉爲完成態,或在失敗時轉爲拒絕態。 then() 方法允許你綁定完成處理函數與拒絕處理函數,而 catch() 方法則只允許你綁定拒絕處理函數;

能夠將多個Promise串聯起來組成Promise鏈,並且能夠在中間傳遞值,甚至是傳遞Promise對象。 then() 的調用都創建並返回了一個新的 Promise ,只有在前一個 Promise 被決議過,新 Promise 也會被決議。 同時也可以使用Promise.all()和Promise.race()方法來管理多個Promise

例子

/**
 * promise 對象是一個構造函數, 用來生成 promise 對象
 * 
 *  resolve 將 promise 對象的狀態從 未完成=> 轉變成 成功, 並且在 異步調用成功之後, 將成功之後的結果 傳遞出去
 *  reject 將 promise 對象的狀態 從 未完成=> 轉變成 失敗, 並且在 異步調用失敗的錯誤作爲參數 傳遞出去  
 * 
 *  promise 實例生成之後 可以分別指定  resolve 狀態和 reject 狀態的 回調函數
 */
    // promise
    var promise = new Promise((resolve, reject) => {
        if (true) {
            resolve();
        } else {
            reject();
        }
    })

    // 例子 一
    function timeFun (ms) {
        return new Promise ((resolve, reject) => {
            setTimeout(resolve, ms, 'done');
        })
    }
    timeFun(100).then(resolve => {
        console.log(resolve) // done
    })

    // 例子二  // promise 一旦建立就會立即執行
    const promiseTwo = new Promise((resolve, reject) => {
        console.log("我是第一個輸出的");
        resolve();
    })

    promiseTwo.then(res => {
        console.log('我是第三個輸出的');
    })

    console.log('我是第二個輸出的')

    /**
     * 輸出結果
     *  promise.js:31 我是第一個輸出的
        promise.js:39 我是第二個輸出的
        promise.js:36 我是第三個輸出的
        promise.js:26 done

        promise 新建之後會立即執行 , 首先輸出第一 , promise 裏面的 resolve 是異步方法, 所以先執行 所有同步再執行異步, 此時 會先輸出 第二, 
        然後再輸出 第三 , 100 之後 會再執行 done 
     */

     // 例子三  promise 實現操作 Ajax 操作
     let promiseAjax = function (url) {
        let promise = new Promise ((resolve, reject) => {
            // 新建一個 對象
            var xhr  = new XMLHttpRequest();
            // 請求方式
            xhr.open('GET', url);
            // 狀態請求改變的回調
            xhr.onreadystatechange = handler;
            // 返回數據格式
            xhr.responseType = 'json',
            xhr.setRequestHeader('Accept', 'application/json');
            xhr.send();
            function handler() {
                if (this.status === 200) {
                    resolve(this.response);
                } else {
                    reject(new Error(this.statusText))
                }
            }
        })
        return promise
     }

     var url  = 'http://httpbin.org/get';
     promiseAjax(url).then(res => {
         console.log('res', res)
     }).catch(error => {
         console.log('error',error)
     })
     
     // 輸出 res null  promise 中的 resolve 跟 reject 都 會帶有參數回傳 , 
     //一個成功之後的參數, 一個失敗之後的, 成功的也可能是 一個 promise 實例, 如 Vue 中的 axios 實例

     /**
      * 要理解 promise 中的 then 方法, 該方法作用是在 Promise 實例狀態改變時的回調函數 , then 方法的第一個參數 是 resolve(成功的) 狀態的回調, 
      * 第二個參數 是 reject(失敗的) 的 狀態的回調 
      *  { 
      *     但是不推薦使用第二個參數-> 推薦使用 catch 進行捕獲錯誤, 原因-> 因爲promise的 狀態一旦改變,就永久保持該狀態, 使用 then 第二個參數識別錯誤,錯誤並不會一直傳遞,
      *     但Promise對象的錯誤具有傳遞性質,它會一直往下傳遞,直到被catch捕獲到爲止。
      *  }, 
      * 還有需要注意的是 then 方法返回的 還是一個 promise 對象. 
      * 所以我們可以使用  鏈式 寫法, then 後面再跟 then 方法 (vue 的 axios 使用)
      * 
      * 如下
      * 
      */

      // then 鏈式寫法
      promiseAjax(url).then(res => {
        console.log(1,res)
        return res
        }).then(val => {
            console.log(2, val) // 返回的是 與上面一直的結果   輸出: 1 null 2 null 
        })

        // 錯誤捕獲案例
        // 不推薦 的寫法
        var p6 = new Promise((resolve, reject) => { });
        p6.then((data) => {
            // success
        }, (error)=>{
            // error
        });
        // 推薦 的寫法
        p6.then((data) => {
            // success
        }).catch((error) => {
            // error
        })
        

這篇文章解析的更爲 詳細易懂.
https://www.jianshu.com/p/063f7e490e9a

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章