1.什么是地狱回调
在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱。
Promise和asyn/await的主要应用场景在于解决地狱回调问题。我们来看以下问题: 以下代码分别定义了吃火锅,喝茶,洗澡三个方法。我们期望的执行顺序也是吃完火锅,再喝茶,最后洗澡。
<script>
//喝茶
function drinkTea(fn){
setTimeout(()=>fn('开始喝茶了...'),2000);
}
//洗澡
function bath(fn){
setTimeout(()=>fn('开始洗澡了....'),3000);
}
//吃火锅
function eatHotPot(fn){
setTimeout(()=>fn('开始吃火锅了...'),5000);
}
eatHotPot(function(resp){console.log(resp)});
drinkTea(function(resp){console.log(resp)});
bath(function(resp){console.log(resp)});
</script>
但是由于吃火锅时间最长,控制台输出顺序如下:
开始喝茶了...
开始洗澡了....
开始吃火锅了...
所以我们必须通过回调函数保证执行顺序,程序改写如下:
<script>
//喝茶
function drinkTea(fn){
setTimeout(()=>fn('开始喝茶了...'),2000);
}
//洗澡
function bath(fn){
setTimeout(()=>fn('开始洗澡了....'),3000);
}
//吃火锅
function eatHotPot(fn){
setTimeout(()=>fn('开始吃火锅了...'),5000);
}
//改写后顺序正确,但是会出现地狱回调现象.
eatHotPot((resp)=>{
console.log(resp);
//吃完火锅喝茶
drinkTea((resp)=>{
console.log(resp);
//喝完茶洗澡
bath((resp)=>{
console.log(resp);
})
})
})
</script>
这样执行结果如下:
开始吃火锅了...
开始喝茶了...
开始洗澡了....
但是这个随着要执行事件的增多,会出现恐怖的地狱回调现象。
2.使用Promise改造
<script>
//喝茶
function drinkTea() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始喝茶了...'), 2000);
})
}
//洗澡
function bath() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始洗澡了....'), 3000);
})
}
//吃火锅
function eatHotPot() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始吃火锅了...'), 5000);
})
}
let promise = eatHotPot();
promise.then((resp) => {
console.log(resp);
return drinkTea();
}).then((resp)=>{
console.log(resp);
return bath();
}).then((resp)=>{
console.log(resp);
})
</script>
输出结果如下:
开始吃火锅了...
开始喝茶了...
开始洗澡了....
3.使用async/await改造
<script>
//喝茶
function drinkTea() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始喝茶了...'), 2000);
})
}
//洗澡
function bath() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始洗澡了....'), 3000);
})
}
//吃火锅
function eatHotPot() {
return new Promise(function (resolve) {
setTimeout(() => resolve('开始吃火锅了...'), 5000);
})
}
async function haveGoodTime(){
//直接获得resolve返回的异步数据。
let hotPot = await eatHotPot();
console.log(hotPot);
let tea = await drinkTea();
console.log(tea);
let myBath = await bath();
console.log(myBath);
}
haveGoodTime();
</script>
这样执行结果如下:
开始吃火锅了...
开始喝茶了...
开始洗澡了....
使用async/await改造使得异步代码的执行更像是同步代码,可读性也变的更好了。