Promise用法總結

看風景就發表於2018-09-14
1. Promise的狀態
 
Promise物件有三個狀態:
1. 進行中(pending)
2. 成功(resolved)
3. 失敗(rejected)
 
2. 生成一個Promise物件
 
1. 建構函式
new Promise(function(resolve,reject){
 
});
resolve和reject函式是瀏覽器內部實現的,直接呼叫即可。
 
2. Promise.resolve
Promise.resolve()直接返回一個resolve狀態的Promise物件
Promise.resolve可以用來生成一個then鏈
 
3. Promise.reject
Promise.reject()直接返回一個reject狀態的Promise物件
 
3. Promise的then的用法

Promise的then永遠返回一個新的Promise,Promise的catch是then(null,rejection)的語法糖,catch中也會返回一個新的Promise。
建議在Promise的then永遠return或throw,不要只是執行一個函式。

例如:
var aPromise = new Promise(function (resolve) {
    resolve(100);
});
var thenPromise = aPromise.then(function (value) {
    console.log(value);
});
var catchPromise = thenPromise.catch(function (error) {
    console.error(error);
});
console.log(aPromise !== thenPromise); // => true
console.log(thenPromise !== catchPromise);// => true
=== 是嚴格相等比較運算子,我們可以看出這三個物件都是互不相同的,這也就證明了 then 和 catch 都返回了和呼叫者不同的promise物件。

1. Promise的then內部可以做三種事情:
 
(1). return 另一個promise
(2). return 一個同步值(或者undefined)
因為javascript函式無返回值時候,預設返回undefined,所以只是執行一個函式,不return,預設就是返回undefined。
返回一個同步值在Promise中會將同步程式碼包裹為promise,得到的還是一個promsie。返回一個同步值是有用處的,例如,
一個非同步值在記憶體中做了快取,可以直接從記憶體中拿到該值,直接返回,不必再呼叫非同步介面。
getUserByName('xxx').then(function(user){
    if(imMemoryCache[user.id]){
        return inMemoryCache[user.id];
    }
    return getUserAccountById(user.id);
}).then(function(userAccount){

});
(3). throw 一個同步異常
 
2. Promise的一些寫法
new Promise(function(resolve,reject){
    resolve(syncValue);
}).then(/*...*/)

//可以寫成
Promise.resolve(syncValue).then(/*...*/)

//一個錯誤也可以寫成
Promise.reject(new Error('...'))
這樣無論成功或失敗都可以後面的then和catch中捕獲和繼續操作
 
3. Promise的then中只能傳遞函式,如果為其他型別,例如另一Promise,會被解釋為null,此時Promsie的值傳遞會穿透
 
例如:
Promise.resolve('foo').then(Promise.resolve('bar')).then(function(result){
    console.log(result);
});
//會被解釋為:
Promise.resolve('foo').then(null).then(function(result){
    console.log(result);
});
第一個resolve的值會穿透到then,列印出foo。
 
4. then的四種寫法的區別
// 寫法一
f1().then(function () {
    return f2();
});

// 寫法二
f1().then(function () {
    f2();
});

// 寫法三
f1().then(f2());

// 寫法四
f1().then(f2);
1. 寫法1和4完全等價,f1值能傳遞到f2,f2的返回值也能繼續向後面的then傳遞
2. 寫法2相當於預設return undefined,無法向後面的then傳遞值
3. 寫法3能夠向後面傳遞f2的值,沒有更深刻的解釋(有懂的朋友請評論告知)

4. Promise的呼叫方法

每個then返回一個新的promise呼叫,這種寫法被稱為composing promises。
promise1.then(function(){
    return promise2;
}).then(function(){
    return promise3;
}).then(function(){
    return promise4;
}).catch(function(err){
    console.log(err);
});
5. Promise的並行執行

由於promise一旦被建立,就會立即執行,所以拿到一個Promise陣列時候,其中的promise必然全部開始執行了。
因此要讓一系列promise順序執行,只能將promise放在一個函式中,在要執行的時候才去建立他,就是一個工廠
函式,promiseFactory。promise並行執行的程式碼應該如下:
function executeSequentially(promiseFactories){
    var res = Promsie.resolve();
    promiseFactories.forEach(function(promiseFactory){
        res = res.then(promiseFactory);
    });
    return res;
}
//工廠函式只是簡單的建立一個promise
function promiseFactory(){
    return createAPromise();
}
6. Promise捕獲錯誤
7. 實現一個Promise版本的ajax
//原生版本
function Http(){

}

Http.prototype = {
    get:function(opts){
        return this.ajax(opts);
    },
    post:function(){
        return this.ajax(opts);
    },
    ajax:function(opts){
        return Promise(function(resolve,reject){
            var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('...');
            var {url,method,data,async,success,fail} = options;
            var sendBody = null;
            var qs = Object.keys(data).reduce(function(cur,pre,index){
                return pre + '&' + encodeURIComponent(cur) + '=' + encodeURIComponent(data[cur]);
            },'').slice(1);
            if(medthod == 'get'){
                url += '?' + qs;
            }
            else if(medhot == 'post'){
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                sendBody = qs || null;
            }
            xhr.onreadystatechange = function(){
                if(xhr.readystate == 4){
                    if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                        resolve(xhr,xhr.responseText);
                    }
                }
                else{
                    reject(xhr,xhr.responseText);
                }
            }
            xhr.open(method,url,async);
            xhr.send(sendBody);
        });
    }
}

//jquery版本
function Http(){

}

Http.prototype = {
    get:function(opts){
        return this.ajax(opts);
    },
    post:function(opts){
        return this.ajax(opts);
    },
    ajax:function(){
        return $.ajax(opts);
    }
}

 

 

參考:https://juejin.im/entry/596f2ab2f265da6c25190f41
     http://javascript.ruanyifeng.com/advanced/promise.html#toc2
   https://www.kancloud.cn/kancloud/promises-book/44256