令人迷惑的Promise chain

最近看一段javascript代码,越看越奇怪,虽然最后问题解决了,但是这段奇怪的代码一直萦绕在我心头,是使用了Promise Chain的代码,今天终于找了点时间,大概了解了下,现在记录下来以备后用。


什么是Promise

字面意思是“承诺”, 官方定义是表示:一个异步事件的完成(失败)以及这个事件的结果。

建议看看MDN's Promise docs,有助于形成一个完整和正确的认识

在javascript中,异步事件的处理一直都是使用回调函数(callback),而Promise正是用来取代callback的。具体Promise的用法不想多说,请查看以上链接。

回到callback 如果若干个异步事件需要按顺序调用的话,就会出现回调函数的嵌套,举个例子, 订披萨和热披萨是两个异步事件,伪代码如下

orderaPizza(function(pizza){

 heatPizza(function(hotPizza){

   eatPizza(hotPizza);

 }) 
})
watchTV()


函数: orderaPizza() 和 heatPizza() 都是异步操作,我并不知道这些操作什么时候完成,所以当我订了披萨(orderaPizza())以后我就去看电视了(watchTV()), 等披萨送来以后会调用我传入的callback方法:heatPizza(), 这也是个异步方法,披萨热了以后会调用我传入的callback方法eatPizza()。 看起来还不错,异步方法按照顺序执行了(orderPizza() --> heatPizza())。但是如果有更多的异步方法需要顺序执行会怎样? 放一张图镇楼!


这就是所谓的callback hell。

这就是Promise Chain适合的场景,放一段代码:

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});

这段代码的output是: 1->2-> 4

初看这段代码其实很混乱:.then()是Promise 对象的成员方法,但是除了行(*)以外,在接下来的.then()内部代码都未曾返回Promise对象,而是返回了一些数值,如:return restult * 2,如果是这样,接下来的.then()应该会报错,因为数值类型是没有.then()的。但是这段代码是可以工作的,所以,谨记以下知识点:

1. .then()(称之为handler)会隐含返回一个Promise

2. 如果handler(in .then())显式return了一个值,这个值会作为隐含返回的Promise的结果,就是callback函数的参数(红色底色)

但是这跟若干个异步函数顺序执行有什么关系?

好的,我们接着说,一般来讲,上一个.then()返回的值会立刻传给下一个.then(), 但是有一个例外: 返回的不是一般的值,是个Promise,这种情况下程序就会suspend,等待最近返回的Promise完成才能继续并且这个Promise执行的结果会作为接下来的.then() callback的输入参数(红色底色)

有木有讲到核心了,但是还是有点晦涩,我们还是看代码:

function orderPizza(){                                    //*0
	return new Promise(function(resolve,reject){      //*1
		resolve("Pizza"); 
	}).then(function(res){                            //*2
		console.log('1-Pay for Pizza');
		return res;                               //*2.1

	});
}

function heatPizza() {                                    //*3
	return new Promise(function(resolve,reject){      //*4
		resolve("hotPizza");
	}).then(function(res){                            //*5
		console.log('3-Could eat?');
		return res;                               //*6   
	});
}

function eatPizza(){                                      //*7
	console.log("5-Enjoy");
}

orderPizza()             //*7.1
.then(function(res){                                      //*8
	console.log("2-Put Pizza in microwave oven");
	console.log(res);                                 //*8.1
	// return res;
	return heatPizza()                                //*9
	.then(function(res){                              //*10
		console.log("4-Put pizza on the table");
		console.log(res);
		return res;                               //*11
	});
})
.then(function(res){           //*12                                      
	eatPizza();                                       //*13
	console.log(res);                                 //*14
});

ouput是:

1-Pay for Pizza
2-Put Pizza in microwave oven
Pizza
3-Could eat?
4-Put pizza on the table
hotPizza
5-Enjoy
hotPizza
这段代码非常有趣,而且涉及到很多的只是,我们一点一点看看。

首先,

1. orderPizza()(*0)返回Promise(*1)并且在函数体内已经注册了一个.then()(*2), 这个.then()返回了一个字符类型(*2.1)。

2. heatPizza()(*3)返回了Promise(*4)并且在函数体内注册了一个.then()(*5),这个.then()返回了一个字符类型(*6)。

3. 调用代码在外层注册了两个.then()(*8和*12), 在第一个.then()函数的内部返回了Promise(*9), 并且注册了一个.then()(*10), 在这个.then()函数体内返回了一个字符类型(*11)。外层的第二个.then()函数内部调用了同步函数eatPizza()(*13和*7)。

根据output我们看一遍执行顺序:

异步函数orderPizza()调用(*7.1)-> 

orderPizza()函数体内注册的.then()(*2)被调用 ->

外部注册的第一个.then()(*8)被调用 ->

上一个被调用的.then()(*8)返回了一个Promise(*9),于是上一个异步的回调被挂起(suspend),开始执行本次返回的异步函数heatPizza()(*9) ->

heatPizza()函数体内注册的.then()(*5)被调用 ->

外部注册的.then()(*10)被调用 ->

最后一个.then()被调用

是不是很复杂,其实只要记住我们前面提到的几个知识点也并不是很难理解,复习下:

1. .then()(称之为handler)会隐含返回一个Promise
2. 如果handler(in .then())显式return了一个值,这个值会作为隐含返回的Promise的结果,就是callback函数的参数(红色底色)
3. 一般来讲,上一个.then()返回的值会立刻传给下一个.then(), 但是有一个例外: 返回的不是一般的值,是个Promise,这种情况下程序就会suspend,等待最近返回的Promise完成才能继续并且这个Promise执行的结果会作为接下来的.then() callback的输入参数

另外一个值得关注的是值得传递.

1.  在.then()中返回的普通值会作为下一个.then()的输入参数。参看(*8.1)print出来的值来自(*2.1),即上一个.then()

2. 在.then()中返回的Promise,它的执行结果会作为接下来.then()的输入参数。参看(*14)实际来源于(*6)然后是(*11)

到这里,该将的知识点就完成了,有两个典型的问题供有兴趣的同学研究:

1. 为啥函数内部注册的.then()先于外面注册的.then()执行呢?

到底哪个.then()先执行呢?

2. 如果在.then()中没有把Promise 返回会怎样?

没返回Promise会怎样?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值