Promise核心基礎

  • 2020 年 7 月 30 日
  • 筆記

基礎

Promise

  • 抽象表達:是js中進行非同步編程的新的解決方案
  • 具體解釋:1、從語法上來說是一個構造函數 2、從功能上來說promise對象用來封裝一個非同步操作並可以獲取其結果
  • 狀態改變:0、new實例為pending(未知)狀態 1、pending變為resolved(成功) 2、pending變為rejected(失敗)
    一個promise對象只能改變一次,成功結果數據一般為value,失敗結果數據一般為reason

示例程式碼

    const p1 =  new Promise
    (
        function(resolve, reject) // 這裡的參數為兩個處理函數,該函數稱為執行器函數(執行非同步任務),該函數為同步回調
        {
            setTimeout
            (
                function()
                {
                    if(Date.now() % 2 === 0)
                    {
                        resolve('成功的數據!');
                    }
                    else
                    {
                        reject('失敗的數據!');
                    }
                },1000
            )
        }
    )

基本使用

        var x;

        function fun1()
        {
            return new Promise
            (
                function(resolve, reject)
                {
                    // 模擬非同步任務
                    setTimeout
                    (
                        function()
                        {
                            console.log('get data successfully'); // 完成數據的接收,並將其處理拋出
                            resolve('datax');
                        },2000
                    )
                }
            )
        }

        fun1().then( (value) => { x = value; console.log(x); } ); // 在回調函數內部將數據輸出

        // 語法糖
        const p1 = Promise.resolve(1); // 構建一個產生一個成功數據為1的promise對象
        const p2 = Promise.reject(0); // 構建一個產生一個失敗數據為0的promise對象

        p1.then( (value) => { console.log(value); } );
        p2.catch( (reason) => { console.log(reason); } );


        // Promise.all
        const allP = Promise.all([p1, p2]); // 參數為一個包含promise對象的數據

        // 對象數組中有一個promise對象返回錯誤就會得到錯誤結果,成功的數據將返回一個數組保存(順序按照對象數組內的順序)
        allP.then( value => { console.log('onResolved') } ).catch( reason => { console.log('onRejected', reason) } );

        // Promise.race 了解(結果為第一個完成的promise實例對象的結果)
        Promise.race([p2, p1]).then( value => { console.log('111') } ).catch( reason => { console.log('000') } );

關鍵問題

  • promise實例對象返回的新promise的結果由指定的對應的回調函數的執行結果來決定
    • 詳細解釋:
      • 如果拋出異常,新的promise狀態為rejected,reason為拋出的異常
      • 如果返回值為任意非promise的值,新的promise狀態變為resolved,value的值為返回的值
      • 若返回值為一個新的promise,則該promise的結果就會稱為新promise的結果

程式碼示例

        new Promise
        (
            function(resolve, reject)
            {
                resolve('正確的輸出結果');
            }
        ).then(value => {console.log('value1', value); return 111;}, reason => {console.log('reason1', reason)}).then(value => {console.log('value2', value)}, reason => {console.log('reason1', reason)});

關鍵問題2

  • 成功或者失敗的回調是非同步的

  • 執行器函數內部的內容是同步執行(關鍵!)

程式碼示例

        new Promise(
            function(resolve, reject){
                setTimeout(
                    function(){
                        resolve('成功返回的數據');
                        console.log('這是resolve語句後的內容');
                    }
                )
            }
        ).then(value => {console.log(value)}).catch(reason => {console.log(reason)});

異常穿透

示例程式碼

        new Promise
        (
            function(resolve, reject)
            {
                reject('onRejected');
            }
        ).then
        (
            value => { console.log('value1', value) },
            // reason => { console.log('reason1', reason) }  // 若不傳入失敗的回調函數,相當於 reason => {throw reason}
        ).then
        (
            value => { console.log('value2', value) },
            // reason => { console.log('reason1', reason) }
        ).then
        (
            value => { console.log('value3', value) },
            // reason => { console.log('reason1', reason) }
        ).catch
        (
            reason => { console.log('reason', reason); return new Promise( ()=>{} ); }  // 返回一個pending狀態的promise實例對象終止鏈式調用
        ).then
        (
            value => { console.log('value4', value) },
            reason => { console.log('reason4', reason) }
        )

宏隊列與微隊列(補充)

  • 宏隊列:dom事件回調、ajax回調、定時器回調
  • 微隊列:promise回調、mutation回調
  • 注意!:在執行每個宏任務前,都要將微任務執行完

示例程式碼

        setTimeout(function(){
            console.log('延遲定時器1');
            Promise.resolve('promise3').then(value => {console.log(value)});
        },0);

        setTimeout(function(){
            console.log('延遲定時器2');
        },0);

        Promise.resolve('promise1').then(value => {console.log(value)});

        Promise.resolve('promise2').then(value => {console.log(value)});