我想点一份火锅和一杯奶茶,但是火锅实在太辣了,必须奶茶先到我才敢吃火锅,所以我希望配送顺序是奶茶先到火锅紧接着再到,如何解决这个问题呢?
function tea(fn){
setTimeout(() => {
fn("奶茶到了")
}, 2000);
}
function hot(fn){
setTimeout(() => {
fn("火锅到了")
}, 1000);
}
tea(function(data){
console.log(data);
hot(function(data){
console.log(data);
})
})
在计时器里面我们无法将参数传递出去,只能通过回调函数,fn就是一个回调函数,调用的时候通过tea(function(){xx})传入一个函数作为实参。为了解决能实现我想要的配送顺序,只有在tea()执行完成也就是奶茶配送到了以后hot()才会执行火锅才会送达。(我要拿到上一个函数返回的结果才能执行下一个函数)
什么是回调地狱
那么如果有多个这样的需求,我要等奶茶到了火锅才到,火锅到了食材才到,食材到了才能清洗,清洗完才能切.....那么代码将会变成这样:
tea(function(data){
console.log(data);
hot(function(data){
console.log(data);
buy(function(data){
console.log(data);
wash(function(data){
console.log(data);
cut(function(data){
console.log(data);
})
})
})
})
})
代码的业务需求仅仅只是用console.log来替代,就已经是一个非常杂乱的状态了,让代码后期难以维护,这就是所谓的回调地狱。
Promise函数
如何解决这样的问题呢,promise给我们带来了解决方案:
let tea = new Promise((resolve,reject) =>{
setTimeout(() =>{
let flag = true;
if(flag){
resolve("奶茶到了")
}else{
reject("奶茶还没到")
}
},2000)
})
let hot = new Promise((resolve,reject) =>{
setTimeout(() =>{
let flag = true;
if(flag){
resolve("火锅到了")
}else{
reject("奶茶还没到")
}
},2000)
})
tea.then((data) =>{
console.log(data);
return hot;
}).then(() =>{
console.log(data);
}).catch((err) =>{
console.log(err);
})
resolve直接将值传递给then方法,reject将值传递给catch,这种方法虽然代码量比上一种会大,但是.then.then这种顺序执行的代码还是比较直观并且易于维护。但是这还是用了很多回调函数啊,下面这种就能很好的解决这个问题。
async/await优化
let tea = new Promise((resolve,reject) =>{
setTimeout(() =>{
let flag = true;
if(flag){
resolve("奶茶到了")
}else{
reject("奶茶还没到")
}
},2000)
})
let hot = new Promise((resolve,reject) =>{
setTimeout(() =>{
let flag = true;
if(flag){
resolve("火锅到了")
}else{
reject("奶茶还没到")
}
},2000)
})
async function asy(){
let Tea = await tea;
console.log(Tea);
let Hot = await hot;
console.log(Hot);
}
asy();
Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它
有没有觉得现在代码可维护性变强了,更加直观了!
await是async函数里面的一个关键字,用法是await加一个promise对象(await Promise),字面意思是等待。
如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
看到上面的阻塞一词,其实不用担心,因为这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。
通过一个奶茶火锅的小故事延伸到异步函数,再到用promise函数解决回调地狱,再然后用async/await进一步优化它。