异步篇:理解Promise

  回调函数有着缺乏顺序性和可信任性的缺陷,而 Promise 是解决这两个缺陷的模式。这篇文章分别通过两个方式来理解 Promise 模式。

第一个方式:未来值

  设想一下,如果某天你突然想要去一个风景区,需要坐高铁。计划好了就去买票。买好了以后,我们获得了一张车票 (Promise,可以乘坐某班次高铁的凭据) ,在高铁出发前的时间,我们都可以在候车厅干自己的事,不用关心时间,因为运行商会通知我们进站。这相当于:车票是一个未来值,代表我们可以坐上某班次高铁。

  我们在候车厅干着自己的事直到高铁运营商通知:“xxx班次列车到站,请抓紧时间进站”。此时,我们就可以用车票进站啦,开始今天计划的旅行。这相当于:我们预定班次的车到达了(需要的值准备好了)我们可以用票换取一段车程(用Promise 换取这个值本身)。

  然而我们进站之后突然听到广播:“xxx班列车出现故障,维护人员正在检修,预计半小时能完成,请乘客们理解并耐心等待!”。即使我们进站了,也可能会发生晚点发车的情况。这里是未来值的另外一个特性:它可能会成功,也可能失败。

  当然还有一种情况,我们买了票,列车因为意外损毁,根本不会进站,我们也不能进站。这相当于 Promise 值永远处于未决议状态。

一. 现在值与将来值

我们在编写代码的时候,通常对一些值做出了基本的假设,它已经是一个具体的现在值了,例:

var a,b = 2;
console.log(a + b); // NaN
  • a + b 这个运算,是我们都已经假定设定值了才编写的。而上面这个例子是想用来模拟一下:a 没有准备好, b 准备好了,期望运算符 “+” 能够检查 a 和 b 都准备好值了再进行运算。这样做并不好,容易引起混乱:因为 “+” 是未来 a,b 准备好之后才执行的,而上面这个例子中,我们并不确定 a 有没有准备好,然而执行了 a + b,产生了意想不到的结果。这样不能确定两条语句的关系,所以不好。
  • 所以,代码里面有的语句现在完成,有的将来完成,容易引起混乱,这么做是没意义的。

那么用回调来实现:把 a 和 b 加起来,如果它们中有没有准备好的,就等它们准备好,然后再加起来。例:

function add(getA,getB,callBack){
	var a,b;
	getA(function(aValue){
		a = aValue;
		if(b !== undefined) callBack(a+b); // 求和
	})
	getB(function(bValue){
		b = bValue;
		if(a !== undefined) callBack(a+b); // 求和
	})
}

add(awardA,awardB,function(sum){
	console.log(sum)
})
  • 上面这个例子中,代码不够简洁,但它体现了一点:为了处理现在和将来,这段代码把它都变成了将来,也就是异步,将来 a 和 b 准备好了,再执行回调函数相加。这里也没有从时间上来观察 a,b 是否可用,对追踪未来值有帮助。
二. Promise值

  Promise 封装了依赖于时间的状态(关注状态),它等待底层值完成或者拒绝,所以 Promise 本身与时间无关。因而,Promise 可以按照可以预测的方式组合,而不用关心时序或底层的结果。

  一旦 Promise 决议,它就永远保持这个状态,此时它成为了不变值,可以根据需求多次查看。这一点是 Promise 设计的基础和重要因素。回调函数也可以组合出类似的这种效果,但是需要重复的一次一次操作。

总结为:Promise 是一种封装和组合未来值的易于复用的机制。

第二个方式:完成事件

  前一个方式是从未来值的方式来看 Promise,这次从另外一个角度看待 Promise 的决议:一种在异步任务中作为两个或更多步骤的流程控制机制。

假设要调用一个函数 fn(…) 执行某个任务,不关心它的任何细节,这个函数可能立即完成任务,也可能需要一段时间才能完成。

  • 在 JavaScript 中监听某个通知,会想到事件。因此,可以用对 fn(…) 发出的一个完成事件的侦听来理解 Promise。
  • 使用回调函数的话,通知就是 fn(…) 调用的回调函数。而使用 Promise 相当于把关系反转了过来,侦听来自 fn(…) 的事件,然后根据得到的通知根据情况继续。
function fn(x){
	// 一段需要时间处理的代码

	// 返回一个事件通知对象
	return listener
}

var event = fn(24);
event.on('complete',function(){
	// 执行下一步
})
event.on('failure',function(err){
	// 表明 fn 中出错了
})
  • 从上面的例子可以看到,我们没有把回调函数传给 fn ,而是返回一个名为 event 的事件注册对象,由它来接受回调。*这里相当于把回调函数反转的控制权右反转了回来。

我们可以把上面的例子看做对 Promise 的模拟,用这种模型来理解 Promise。

-------------------- 参考书籍 《你不知道的JavaScript》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值