一、什么是回调地狱
1、什么是回调函数
在一个函数里面以形参的方式调用一个传递进来的函数。
function a(callback) {
callback()
}
a(function () {})
假设我们想同时拿到3个异步执行的结果,这时就可以通过异步回调函数嵌套调用的方式解决。例如用ajax异步请求:
//这里的用的是ajax的封装
ajax({
url:"http://localhost/promise/data/d1.php",
success:function(res1){
console.log(res1);
ajax({
url:"http://localhost/promise/data/d2.php",
success:function(res2){
console.log(res2);
ajax({ url:"http://localhost/promise/data/d3.php",
success:function(res3){
console.log(res3);
console.log(res1, res2, res3);
}
})
}
})
}
})
但是回调函数嵌套过多会形成一个回调地狱。 回调地狱虽然能解决同时拿到3个异步执行的结果,但会使代码变得不优雅、可读性差,不便于维护。 我们可以用下方式解决。
二、回调地狱的解决方式
在js新版本出现之前,回调地狱自身就是解决方式, 新版本出现之后,在新的语法中,提供了一些更优雅的处理方案
1、使用 Promise 的语法解决
Promise 的三个状态
(1)Pending :异步的事情正在执行
(2)Fulfilled :异步的事情成功了
(3)Rejected :异步的事情失败了
Promise 的基本语法
Promise是一个构造函数,new的同时立即传参,参数是回调函数,回调函数身上可以接受两个参数,分别是:resolve(表示成功),reject(表示失败)
let p = new Promise(function (resolve, reject) {
// 在这里做一个异步的事情
//resolve就是在then中的第一个回调函数,表示成功要做的事情
//reject就是在catch中的第一个回调函数,表示失败要做的事情
})
p.then(function(){
// 成功的预置函数
})
p.catch(function(){
// 失败的预置函数
})
Promise 的链式调用
let p = new Promise(function (resolve, reject) {
// 在这里做一个异步的事情
}).then(function () {
return new Promise(function () {
// 第二个异步的事情
})
}).then(function () {
})
Promise 的批量处理 – all (全部成功,即为成功,只要有一个失败,即为失败 )
let p1 = new Promise( function (resolve, reject){ } );
let p2 = new Promise( function (resolve, reject){ } );
let p3 = new Promise( function (resolve, reject){ } );
Promise.all( [p1, p2, p3] ).then(function () {
}).catch(function(){
})
Promise 的批量处理 – race (得到最先结束的状态,不管是成功还是失败)
let p1 = new Promise( function (resolve, reject){ } );
let p2 = new Promise( function (resolve, reject){ } );
let p3 = new Promise( function (resolve, reject){ } );
Promise.race( [p1, p2, p3] ).then(function () {
}).catch(function(){
})
总的来说Promise是用来处理所有的异步的回调地狱,不止是ajax,任何一个异步,只是是回调地狱的调用形式,就可以使用promise改造。
2、在Promise的基础上,再使用async/await(ES7)
async / await 是 ES7( ES2016 ) 的新增语法,是回调地狱的终极解决方案,我们就是用 async / await 语法把 异步代码写的看起来像同步代码,把代码写的更优雅。
(1)async 关键写写在函数的前面, 就把该函数变成了一个异步函数
(2)await 是一个写在 异步函数 里面的关键
(3)await 关键字后面的必须是一个 Promise 对象
有了以上三个条件, 我们就可以把本该在 promise 的 then 回调里面接受的结果,放在 await 关键字前面定义一个变量来接受了.
async function goHome() {
let result = await new Promise(function () { … })
// 这里的代码会在上面的 promise 结束以后在执行
console.log(result)
}