title: promise使用初探
date: 2018-12-29 16:10:48
categories: 小游戏
tags: js
promise简介
Promise
是异步编程的一种解决方案,比传统的解决方案 --- 回调函数和事件——更合理和更强大。
为什么要用他
我们考虑这么一个场景,我们需要登陆拿到用户的token,然后再利用用户的token取取用户的信息,最后利用用户的相关信息去拿他的好友的相关信息。假设我们提供如下的模拟接口:
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)
}
}
那么直接用回调来实现的话,我们的调用如下:
var api = new Api();
api.getToken((token) => {
// 获得了token
api.getUserInfo(token, (userInfo) => {
// 获得了userInfo
api.getOtherInfo(userInfo, (getOtherInfo) => {
console.log(" get other info " + getOtherInfo);
})
})
})
一个很常见的场景,但是我们直接用callBack来实现的话,就会这么多嵌套的回调,这只是一个很简单的例子,试想一下,如果需求更复杂一点的话,回调就会更加复杂,如果要考虑代码的健壮性的话,加上异常处理,那简直就不能忍受了。
在这个时候,promise
就站出来了,我们可以通过使用他,大大简化代码的嵌套,避免回调地狱。
promise简单用法
我们稍微调整一下前面的api,我们使用Promise
的方式来实现,调整如下:
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``之后,那么我们的调用怎么去调用呢?很简单,如代码所示:
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
之后,代码明显简化了很多。
不知道是怎么看简化的,明显更复杂好吧。
不要着急,我们可以可以一步一步来进行简化。下面开始我们的简化之旅。
promise的链式用法
Promise
有一个很棒的特性:Promise.prototype.then()
和Promise.prototype.catch()
返回Promise对象,这就使得我们可以将这些promise
连接成一个promise
链。通过这种方法,我们可以将这些回调函数放在一个缩进层次里。与此同时,我们使用了箭头函数简化了回调函数声明。
对比之前的回调地狱,使用promise
链使得代码的可读性大大提高并且拥有着更好的序列感。
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);
});
是不是明显就没有那么多回调了,看着是不是舒服多了。哈哈,不过这还没完,这代码看起来还是稍微有点复杂,虽然没有一层一层的回调了,但是链起来好像也有点长,让我们继续来优化他。
使用Async/Await将异步“变”同步
我们首先来看调用的函数代码:
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);
}
是不是顿时感觉就清爽很多了。
我们可以通过
await
将回调“变”成同步方法来使用,我们只有执行完了api.getToken
之后,才能继续执行下面的方法。前提是必须要在异步方法里,即被async
修饰的方法里面。从上面的方法来说,我们可以将它当作一个同步方法来使用了。
异常处理
我们先来看,如果使用回调的话,如果要进行异常处理该怎么写吧。
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
,是不是双爽歪歪,如果我们还要加入流程控制、异常处理,这简直就是异常灾难。那么我们接下来看怎么用Promise
进行异常处理。
先上代码:
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);
});
链式的调用,我们只需要在在后面加上一条异常处理的catch()
即可,和前面的若干个try-catch
相比是不是简单很多。当然,我们也可以用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);
}
}
总结
通过使用Promise
,可以大大简化我们回调的嵌套,可以使得我们的代码更加简洁、易读。