回调地狱
回调地狱指多个回调函数嵌套
还记得回调函数吗? 就是调用自身啊
下面用代码解释写法繁琐但写法合法的回调地狱 :
首先创建三个json文件 : a.json b.json c.json
内容分别为 : {"aa" : "hello"} {"bb" : "world"} {"cc" : "html"}
$.ajax({
url:"a.json",
dataType:"json",
success(data){ //请求到a的数据之后再去请求b的数据
$.ajax({
url:"b.json",
dataType:"json",
success(data){ //请求到b的数据之后,再去请求c的数据
$.ajax({
url:"c.json",
dataType:"json",
success(data){
console.log(data); //{cc : "html"}
}
})
}
})
}
})
Promise对象
Promise对象主要把回调函数嵌套的写法变成链式写法
Promise对象里放的是异步操作的代码,异步操作的代码的状态会从等待状态变为成功状态或者是失败状态,当他的状态发生改变的时候就会触发.then方法,.then方法里有两个函数,第一个是成功的函数,第二个是失败的函数
jq的 $.ajax返回的本身就是一个promise对象,可以直接调用then方法,假设$.ajax返回的不是promise的话我们需要自己new Promise方法 ,才能调用then方法
(1) 一个ajax请求的时候
// 原生的写法
function js_pro(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var data = xhr.responseText;
resolve(data);
} else {
reject("404");
}
}
}
})
}
js_pro("a.json").then(res=>{
delDate(res); //成功的回调函数中可以使用封装函数
},res=>{
})
function delDate(data){
console.log(data); // {aa : "hello"}
}
//jq写法
function jq_pro(url,data){
return $.ajax({
url,
data,
dataType:"json",
})
}
jq_pro("a.json").then(res=>{
delDate(res);
},res=>{
})
(2) 多个ajax请求的时候 ( 回调地狱 ) , 返回新的promise实例 , 可以链式调用
// 原生的写法
function js_pro(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var data = xhr.responseText;
resolve(data);
} else {
reject("404");
}
}
}
})
}
js_pro("a.json").then(res=>{
return js_pro("b.json");
}).then(res=>{
return js_pro("c.json");
}).then(res=>{
console.log(data); //{cc : "html"}
})
//jq写法
function jq_pro(url,data){
return $.ajax({
url,
data,
dataType:"json",
})
}
jq_pro("a.json").then(res=>{
return jq_pro("b.json");
}).then(res=>{
return jq_pro("c.json");
}).then(res=>{
console.log(data); //{cc : "html"}
})
(3) 多个ajax请求的时候 ( 互相没有关系 ) Promise.all
当页面中有多个ajax请求,而且他们之间没有关系,就可以用promise.all发送多个promise异步操作 , 只有这多个异步请求全都成功了才会执行then方法
function jq_pro(url,data){
return $.ajax({
url,
data,
dataType:"json"
})
}
Promise.all([
jq_pro("a.json"),
jq_pro("b.json"),
jq_pro("c.json")
]).then(res=>{
console.log(res); //[{aa:"hello"},{bb:"world"},{cc:"html"}]
})
Promise . race 请求多个promise , 只要有一个响应成功了就会触发.then
Promise.race([
jq_pro("a.json"),
jq_pro("b.json"),
jq_pro("c.json")
]).then(res=>{
console.log(res); //{aa:"hello"}或{bb:"world"}或{cc:"html"}看哪个json文件先响应
})
promise的错误处理有两种写法:
- then 方法里放两个函数 , 第一个是成功的回调 , 第二个是失败的回调
- then 方法里放成功的回调,继续.catch放失败的回调 jq 的 ajax 比较特殊,因为他是自己已经封装好的promise对象,catch的写法变成了fail
catch会捕捉到错误 , 之后的代码不执行
(1) 一个ajax的错误处理
// jq写法
function jq_pro(url,data){
return $.ajax({
url,
data,
dataType:'json'
})
}
jq_pro("a.json").then(res=>{
console.log(res);
}).fail(res=>{
console.log(res);
})
// js写法
function js_pro(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var data = xhr.responseText;
resolve(data);
} else {
reject("404");
}
}
}
})
}
js_pro("a.json").then(res=>{
console.log(res);
}).catch(res=>{
console.log(res);
})
(2) 多个ajax回调地狱的错误处理
js_pro("a.json").then(res=>{
return js_pro("b.json");
}).then(res=>{
return js_pro("c.json");
}).then(res=>{
console.log(res);
}).catch(res=>{
console.log(res);
})
(3) 多个ajax没有关系
Promise.all([
js_pro("a.json"),
js_pro("b.json"),
js_pro("c.json")
]).then(res=>{
console.log(res);
}).catch(res=>{
console.log(res);
})