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)潔、易讀。