回调地狱
在没有学会promise之前,当我遇到连续使用多个ajax请求的情况,并且做ajax请求时,这个新的ajax请求的其中一个参数,得从上一个ajax请求中获取时,就需要回调函数套回调函数了,就很可能出现回调地狱的情况
比如以下代码,注释是精华
//假设我已经引用了jQuery
$("button").click(function(){
$.get("demo_test.asp",function(result){
console.log("假装这里有一些代码");
//这里就需要拿到这次ajax请求返回的数据,拼接成新的url,用于再次发起第二个ajax请求,所以第二个请求要写在第一个请求的callback中
var url = "demo_test.asp?name:"+result;
$.get(url,function(result2){
console.log("假装这里又有一些代码");
/*
如果我还要发第三个请求,而且第三个请求需要用到第二个请求返回的数据,
那么又需要将第三个请求写在第二个请求的callback中的,我们再极端的想想,
如果这样的情况要重复10次,20次,那样就会有10个,20个回调函数套回调
函数这样就会出现回调地狱了。然鹅,Promise很好的解决了这个问题。
*/
});
});
});
看看Promise如何解决回调函数
//假设我已经引用了jQuery
function test(){
$.get("demo_test.asp",function(result){
console.log("假装这里有一些代码");
// 返回Promise对象
return new Promise(function(resolve) { //这里还可以传入第二个参数reject(可选)
resolve(result);
});
});
};
$("button").click(()=>{
test()
.then((result)=>{
var url = "demo_test.asp?name:"+result;
return url;//返回一个Promise对象,带有参数url,可以直接在下一个then中使用
})
.then((url)=>{
$.get(url,function(result2){
console.log("假装这里又有一些代码");
return result2; //这里又可以把请求的结果返回出来,接着用then做下一个请求
});
})
.then((result2)=>{
//巴拉巴拉又是一堆代码
})
});
这样就完美地解决了回调地狱的问题啦
下面再看一组代码,更加熟悉一下Promise的用法
以下代码来自 作者:这波能反杀,来源:简书
function want() {
console.log('这是你想要执行的代码');
}
function fn(want) {
console.log('这里表示执行了一大堆各种代码');
// 返回Promise对象
return new Promise(function(resolve, reject) {
if (typeof want == 'function') {
resolve(want); //等函数执行后,执行resolve(),resolve()就是我们在下面 .then()里面写的第一个函数,第二个函数可以不写(第二个函数是reject())
} else {
reject('TypeError: '+ want +'不是一个函数')
}
})
}
fn(want).then(function(want) {
want();
})
fn('1234').catch(function(err) {
console.log(err);
})
再来看看Promise.all
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
上面这段话引用至https://www.jianshu.com/p/7e60fc1be1b2,作者:李悦之,来源:简书
我们接下来来看看下面这段代码
来自:破解前端面试(80% 应聘者不及格系列):从 闭包说起
const tasks = [];
for (var i = 0; i < 5; i++) {
((j) => {
tasks.push(new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, j);
resolve(); // 这里一定要 resolve,否则代码不会按预期 work
}, 1000 * j); // 定时器的超时时间逐步增加
}));
})(i);
}
Promise.all(tasks).then(() => { //这个resolve没有传参数,如果传入参数,就会去获取每一个Promise的resolve传递的值,收集为一个数组,作为这个resolve()的参数,如果不太明白,可以看下一个例子
setTimeout(() => {
console.log(new Date, i);
}, 1000); // 注意这里只需要把超时设置为 1 秒
});
/*
每隔一秒输出一行
Tue Oct 09 2018 16:26:19 GMT+0800 (中国标准时间) 0
Tue Oct 09 2018 16:26:20 GMT+0800 (中国标准时间) 1
Tue Oct 09 2018 16:26:21 GMT+0800 (中国标准时间) 2
Tue Oct 09 2018 16:26:22 GMT+0800 (中国标准时间) 3
Tue Oct 09 2018 16:26:23 GMT+0800 (中国标准时间) 4
Tue Oct 09 2018 16:26:24 GMT+0800 (中国标准时间) 5
*/
我们对上面的那段代码进行小小的改造
const tasks = [];
for (var i = 0; i < 5; i++) {
((j) => {
tasks.push(new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, j);
resolve(j); // 传参j,如果里面没有传参,下面的Promise.all就会等到一个length为5的数组,值都是undefined
}, 1000 * j); // 定时器的超时时间逐步增加
}));
})(i);
}
Promise.all(tasks).then((i) => { //这里的i表示一个数组[0,1,2,3,4]
setTimeout(() => {
console.log(new Date, i); //猜猜这里会输出什么?
}, 1000);
});
/*
每隔一秒输出一行
Tue Oct 09 2018 16:26:19 GMT+0800 (中国标准时间) 0
Tue Oct 09 2018 16:26:20 GMT+0800 (中国标准时间) 1
Tue Oct 09 2018 16:26:21 GMT+0800 (中国标准时间) 2
Tue Oct 09 2018 16:26:22 GMT+0800 (中国标准时间) 3
Tue Oct 09 2018 16:26:23 GMT+0800 (中国标准时间) 4
Tue Oct 09 2018 16:32:30 GMT+0800 (中国标准时间) (5) [0, 1, 2, 3, 4]
*/
现在是不是对Promise有个简单的了解啦