讀書筆記-你不知道的JS中-promise(2)


繼續填坑

模式

  考慮下面的代碼:

    function fn(x) {
        //do something
        return new Promise(function(resolve, reject) {
            //調用resolve(..)和reject(...)
        });
    }
    var p = fn(2);

  new Promise(..)模式通常稱為revealing constructor。傳入函數會立即執行(不會像then(..)中的回調一樣異步延遲),它有兩個參數,分別為resolve和reject。這些是promise的決議函數。resolve通常標識完成,reject標識拒絕。

 

鴨子類型

  如何判斷一個對象是不是一個Promise?雖然promise是通過new Promise(..)創建的,但是無法通過instanceof Promise來檢測,最主要的原因是promise可能來自其他的窗口,檢查無法識別這樣的Promise實例。

  識別Promise的方法被定義為是否具有then方法。也就是說,任何對象和函數,如果有then(包括原型鏈上)方法,就認為是一個Promise對象。

  邏輯大概如下:

    if (
        p !== null &&
        (typeof p === 'object' || typeof p === 'function') &&
        typeof p.then === 'function'
    ) {
        //這是一個promise對象
    }

 

Promise特點

  1、對一個Promise調用then時,提供的回調永遠會被異步調用。

  2、只要promise被決議,提供給then的回調會被自動調用,永遠返回一個值。

 

promise與競態

  雖然說一旦promise被決議,后續then方法的回調一定會被調用,但是決議本身未被執行,只能通過別的機制來強制執行:

    //必須返回一個promise
    function delay(time) {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                reject('time out');
            }, time);
        });
    }
    //3秒內未決議就會被reject
    Promise.race(p, delay(3000)).then(function() {
        //success
    }, function(err) {
        //failed
    })

 

  

Promise異常

  考慮下面的代碼:

    var p = new Promise(function(resolve, reject) {
        //異常
        fo();
    })
    p.then(function(data) {
        console.log(data);
    }, function() {
        //這個reject接受了異常 並又搞出了一個異常
        foo();
    }).then(function() {

    }, function() {
        //這個reject處理了最后的異常
        console.log(1);
    });

  可以看出,每一個then方法會返回一個promise,並且一旦決議就不會改變,異常會轉接到下一個then的reject。

 

 Promise的回調

  看起來promise也是利用回調函數完成異步操作,但是有一些不同。

 

關於Promise.resolve(..)

  如果向Promise.resolve(..)傳遞一個非Promise、非thenable(即有then方法的對象或函數)的立即值,就會得到一個用這個值填空的promise,相當於包裝。

  下面兩種情況,p1和p2的行為是一樣的:

    var p1 = new Promise(function(resolve, reject) {
        resolve(42);
    });
    var p2 = Promise.resolve(42);
    console.log(p2); //Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 42}

  而如果向Promise.resolve(..)傳遞一個真正的Promise,就只會返回同一個promise。

    var p1 = Promise.resolve(42);
    var p2 = Promise.resolve(p1);
    console.log(p1 === p2); //true

  如果向Promise.resolve(..)傳遞了一個非Promise的thenable值,前者會試圖展開這個值,而且展開過程會持續到提取出一個具體的非類Promise的最終值。

  比如說:

    var p = {
        then: function(resolve, reject) {
            resolve(42);
            // reject('123');
        }
    };
    p.then(function resolve(val) {
        console.log(val);
    }, function reject(err) {
        console.log(err);
    });
    Promise.resolve(p); //打印42 得到一個Promise

  Promise.resolve(..)可以接受任何thenable,將其解封為非thenable的值。從Promise.resolve(..)得到的肯定是一個Promise,是一個可信任的值。

  將一個未知工具封裝Promise並解析,可以這樣:

    Promise.resolve('tool').then(function(val) {
        console.log(val);
    });

  這樣,可以將所有未知封裝為Promise,保證異步調用。

 

 鏈式調用

  可以把多個Promise連接到一起以表示一系列異步步驟:

  1、每次調用then(..),它都會創建並返回一個新的Promise,我們可以將其鏈接起來。

  2、不管從then(..)調用的完成回調返回的值是什么,都會被設置為被鏈接Promise。

  不太懂啊:

    var p = Promise.resolve(2);
    var p2 = p.then(function(v) {
        console.log(v); //2
        return v * 2;
    });
    p2.then(function(v) {
        console.log(v); //4
    });

  通過Promise.resolve對2進行封裝,調用第一個then方法得到數據2。接着返回一個包含4的Promise封裝對象,由調用then方法獲取到4。

  只要通過return和then方法,就能實現Promise鏈式調用。

 

Ajax案例

  鏈式調用可以與ajax完美結合,如下例:

    //假設存在方法ajax(url,callback)
    function request(url) {
        return new Promise(function(resolve, reject) {
            //ajax的回調函數是promise的resolve()函數
            ajax(url, resolve);
        });
    }
    //異步請求返回數據data
    request('http://...').then(function(data) {
        //將返回的數據拼接到第二個url作為參數再次請求
        return request('http://...?data=' + data);
    }).then(function(data2) {
        //得到最終數據
        console.log(data2);
    });

  如果then方法參數未提供resolve或者reject,會有一個默認的函數生成,如下例:

    Promise.resolve(2).then(
        //function(v){
        //    return v;
        //}
        null,
        function() {
            console.log(1);
        }).then(function(v) {
            console.log(v); //2
        },
        //默認錯誤處理函數
        //function(err) {
        // throw err;
        //}
    );

   

  小結:1、調用Promise.resolve(..)與then(..)總會返回一個Promise。

     2、決議后返回的值可以通過鏈式調用解決掉。

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM