promise使用初探


title: promise使用初探
date: 2018-12-29 16:10:48
categories: 小游戲
tags: js


promise簡(jiǎn)介


Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案 --- 回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。

為什么要用他

我們考慮這么一個(gè)場(chǎng)景,我們需要登陸拿到用戶的token,然后再利用用戶的token取取用戶的信息,最后利用用戶的相關(guān)信息去拿他的好友的相關(guān)信息。假設(shè)我們提供如下的模擬接口:

class Api{

    getToken(callBack) {
        setTimeout(() =>{
            callBack && callBack("123");
        }, 200);    
    }

    getUserInfo(token, callBack) {
        setTimeout(() => {
            callBack && callBack(token + "4");
        }, 200)
    }

    getOtherInfo(id, callBack) {
        setTimeout(() => {
            callBack && callBack(id + "5");
        }, 200)
    }
}

那么直接用回調(diào)來實(shí)現(xiàn)的話,我們的調(diào)用如下:

var api = new Api();

api.getToken((token) => {
    // 獲得了token
    api.getUserInfo(token, (userInfo) => {
        // 獲得了userInfo
        api.getOtherInfo(userInfo, (getOtherInfo) => {
            console.log(" get other info " + getOtherInfo);
        })
    })
})

一個(gè)很常見的場(chǎng)景,但是我們直接用callBack來實(shí)現(xiàn)的話,就會(huì)這么多嵌套的回調(diào),這只是一個(gè)很簡(jiǎn)單的例子,試想一下,如果需求更復(fù)雜一點(diǎn)的話,回調(diào)就會(huì)更加復(fù)雜,如果要考慮代碼的健壯性的話,加上異常處理,那簡(jiǎn)直就不能忍受了。
在這個(gè)時(shí)候,promise就站出來了,我們可以通過使用他,大大簡(jiǎn)化代碼的嵌套,避免回調(diào)地獄。

promise簡(jiǎn)單用法

我們稍微調(diào)整一下前面的api,我們使用Promise的方式來實(shí)現(xiàn),調(diào)整如下:

class Api2{

    getToken() {
        return new Promise((reslove, reject) => {
            setTimeout(() =>{
                reslove && reslove("123");
            }, 200); 
        }) 
    }

    getUserInfo(token) {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove && reslove(token + "4");
            }, 200)
        })
    }

    getOtherInfo(id) {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove && reslove(id + "5");
            }, 200)
        })
    }
}

在使用了```Promise``之后,那么我們的調(diào)用怎么去調(diào)用呢?很簡(jiǎn)單,如代碼所示:

var api = new Api2();

api.getToken().then(function(reslove, reject) {
    console.log("token = "+ reslove);
    api.getUserInfo(reslove).then((reslove, reject) => {
        console.log("info = "+ reslove);
        api.getOtherInfo(reslove).then((reslove, reject) => {
            console.log("friend Id = "+ reslove);
        });
    });
})

可以看到,在使用了Promise之后,代碼明顯簡(jiǎn)化了很多。


不知道是怎么看簡(jiǎn)化的,明顯更復(fù)雜好吧。
不要著急,我們可以可以一步一步來進(jìn)行簡(jiǎn)化。下面開始我們的簡(jiǎn)化之旅。

promise的鏈?zhǔn)接梅?/h2>

Promise有一個(gè)很棒的特性:Promise.prototype.then()Promise.prototype.catch()返回Promise對(duì)象,這就使得我們可以將這些promise連接成一個(gè)promise鏈。通過這種方法,我們可以將這些回調(diào)函數(shù)放在一個(gè)縮進(jìn)層次里。與此同時(shí),我們使用了箭頭函數(shù)簡(jiǎn)化了回調(diào)函數(shù)聲明。
對(duì)比之前的回調(diào)地獄,使用promise鏈?zhǔn)沟么a的可讀性大大提高并且擁有著更好的序列感。

var api = new Api2();

api.getToken().then((reslove, reject) => {
    console.log("token = "+ reslove);
     return api.getUserInfo(reslove);
}).then((userInfo) => {
    return api.getOtherInfo(userInfo);
}).then((friendInfo) => {
    console.log("friend id = " + friendInfo);
});

是不是明顯就沒有那么多回調(diào)了,看著是不是舒服多了。哈哈,不過這還沒完,這代碼看起來還是稍微有點(diǎn)復(fù)雜,雖然沒有一層一層的回調(diào)了,但是鏈起來好像也有點(diǎn)長,讓我們繼續(xù)來優(yōu)化他。

使用Async/Await將異步“變”同步

我們首先來看調(diào)用的函數(shù)代碼:

async function getFriend() {
    const api = new Api2();
    const token = await api.getToken();
    const userInfo = await api.getUserInfo(token);
    const friend = await api.getOtherInfo(userInfo);
    console.log("friend " + friend);
}


是不是頓時(shí)感覺就清爽很多了。
我們可以通過await將回調(diào)“變”成同步方法來使用,我們只有執(zhí)行完了api.getToken之后,才能繼續(xù)執(zhí)行下面的方法。前提是必須要在異步方法里,即被async修飾的方法里面。從上面的方法來說,我們可以將它當(dāng)作一個(gè)同步方法來使用了。

異常處理

我們先來看,如果使用回調(diào)的話,如果要進(jìn)行異常處理該怎么寫吧。

var api = new Api();

try{
    api.getToken((token) => {
        // 獲得了token
        try{
            api.getUserInfo(token, (userInfo) => {
                // 獲得了userInfo
                try{
                    api.getOtherInfo(userInfo, (getOtherInfo) => {
                        console.log(" get other info error" + getOtherInfo);
                    })
                } catch(e) {
                    console.log("getOtherInfo " + e);
                }
            })
        } catch(e) {
            console.log("getUserInfo error" + e);
        }
    })    
} catch(e) {
    console.log("getToken error" + e);
}

這么多try-catch,是不是雙爽歪歪,如果我們還要加入流程控制、異常處理,這簡(jiǎn)直就是異常災(zāi)難。那么我們接下來看怎么用Promise進(jìn)行異常處理。

先上代碼:

api.getToken().then((reslove, reject) => {
    console.log("token = "+ reslove);
     return api.getUserInfo(reslove);
}).then((userInfo) => {
    return api.getOtherInfo(userInfo);
}).then((friendInfo) => {
    console.log("friend id = " + friendInfo);
}).catch((err) =>  {
    console.log("error " + err);
});

鏈?zhǔn)降恼{(diào)用,我們只需要在在后面加上一條異常處理的catch()即可,和前面的若干個(gè)try-catch相比是不是簡(jiǎn)單很多。當(dāng)然,我們也可以用awit-async組合+try-catch來處理異常。示例代碼如下:

async function getFriend() {
    try{
        const api = new Api2();
        const token = await api.getToken();
        const userInfo = await api.getUserInfo(token);
        const friend = await api.getOtherInfo(userInfo);
        console.log("friend " + friend);
    } catch(e) {
        console.error("error: "+ e);
    } 
}

總結(jié)

通過使用Promise,可以大大簡(jiǎn)化我們回調(diào)的嵌套,可以使得我們的代碼更加簡(jiǎn)潔、易讀。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容