Promise的使用——解决回调地狱

回调地狱

在没有学会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有个简单的了解啦

猜你喜欢

转载自blog.csdn.net/Mr_lizi/article/details/82979523