Promise (一)
有意图写下以下关于promise的几篇文章,目的在于将自己最近对于promise的学习归纳、总结出来,同时由于一方面是通过自己学习的一家之言,另一方面也是通过对各种鱼龙混杂疏通和整理加上自己的感悟,发布在社区里面希望各位能够提点一二。
当我们去深入学习、研究一个东西,我们一定会问自己,这个东西有什么用处,有什么好处,能为我们带来什么。
那么为什么用promise?下面是我能想到的大部分人的答案。
1 用异步的方式来表达异步的代码是艰难的。我们需要一种以同步的代码来尽可能隐藏具体的异步实现的方式以方便理解,而promises能满足这个需求。当使用promise编码时候,我们以同步的方式来编码而不需要关心它的实现的同步还是异步。
2 方便编写出更加优美的代码,消除node原生的回调函数在代码外观上显示出来的由于不断缩进所形成的金字塔。
......
如果你想到的是上面两点,那么,我在这里,想要更深入一点地谈一下promise。
promise是什么
这是最通俗的一个问题。
没错,promise就是一个状态的容器,是一个异步的、非暂存的、不可变的值。
异步: 这个值可能现在就存在,也可能是将来某个时刻的一个值。
非暂存: 无论promise最后的结果是什么(success或者failure),他就不会改变了,你总是可以获得这个消息只要你不销毁promise。
不可变: 一旦一个promise的状态变为resolved或rejected,就不能改变也不会改变,即完成的promise是不可变的。
promise的可靠性
promise的可靠性是我们所关注的,这是promise的精髓所在,promise可靠性即为完成的promise是不可变的,promise的这个特性的好处有两点:
1 与原生回调不同,promise只会运行一次,然后就不用了。
2 可预测性。
promise的作用并不简单是关于处理回调的嵌套和缩进
当然我首先不否认,promise可以处理异步回调的嵌套和缩进,但这不是关键。
首先抛出一个问题,回调真正的问题在哪儿?你可以静下来思考一下看你对这个问题是否陌生,而你的理解又是否正确、是否能说服你自己。来看下面一段代码。
// 1 balabalabala
aAsyncFuc(function(){
// 2 heiheieheihei
}) ;
我们需要思考的一个问题是,在代码1 和代码2之间发生了什么?这之间是谁在进行代码的流程控制。
表层上看来,是aAsyncFuc(..)控制着这些。是你自己创建并管理aAsyncFuc()吗?许多时候不是,这个aAsyncFuc很多时候可能是你所使用的一个第三方库中的一个方法。那么当aAsyncFuc(..)是一个第三方库中的一个方法时,你信任这个第三方库吗?
你会问,信任什么?信任就是你以为这个aAsyncFuc(..)会很完美地做到下面这些:
不会太早调用我的回调函数
不会太迟调用我的回调函数
不会少于实际应该调用的次数,比如不会漏掉函数调用
不会多于实际应该调用的次数,比如重复调用
会给我的回调提供必要的参数
在我的回调失败的时候会提醒我
.......
你是如此地信任这个第三方类库中的方法,导致在不知不觉中你把你的代码控制权转交给了这个你实际上并不那么信任的第三方库。
在你的程序的前半部分,你控制着程序的进程。现在你转移了控制权,aAsyncFuc(..)控制了你剩余程序什么时候返回以及是否返回。
像这样一个简单的回调就会把你的控制权转移出去,那么当你编写许多深层次的嵌套回调的时候,可以想象一下控制转移的增长性以及这种转移控制的危害性。
那么,如何解决?
现在npm上的那些第三方类库,面向你都是免费的,人家都没跟你要钱,你爱用不用,但有些确实是融合了作者的智慧,使用这些包能让你节省很多劳力和脑力,但是我们也不可能去对每个要用到的第三方包孜孜以求,查源码,测试每一个函数输入输出的正确性......这个时候,promise机制的卓越性就体现出来了。
promise改变了传递回调的地方。
在此之前,我先给大家温习一下标准promise机制的保证。
如果promise被resolve,它要不是success就是failure,不可能同时存在。
一旦promise被resolve,它就再也不会被resolve(不会出现重复调用)。
如果promise返回了成功的信息,那么你绑定在成功事件上的回调会得到这个消息。
如果发生了错误,promise会收到一个带有错误信息的错误通知。
无论promise最后的结果是什么(success或者failure),他就不会改变了,你总是可以获得这个消息只要你不销毁promise。
我们回到“promise改变了传递回调的地方”这句话,这里所说的“地方”就是promises机制,通过传递回调给拥有良好保证和可预测性的中立Promises机制,这个时候promise机制帮助我们把我们处理任何函数调用的成功或者失败的方式规范成了可预测的形式,特别是如果这个调用实际上的异步的。 从而使得你实质上重新获得了对于后续程序能很稳定并且运行良好的可靠性。与原生的回调函数是将回调传递给你所调用的第三方库中的API相比,当你进行深层次异步调用的时候,你的控制转移都是交给了中立的Promise机制,而不是将你的代码流程控制权转交给在你没有对其进行源码分析的第三方类库。
下一篇,我将根据我的理解对promise链接起来进行流程控制进行分析,具体涉及到promise链控制异步和同步操作,内存泄漏以及promise典型的且重要的错误处理。
另外,为什么我用markdown写出来的东西这么丑,有点不能忍…