开发者的javascript造诣取决于对【动态】和【异步】这两个词的理解水平。
一. 别人是开发者,你也是Promise技术是【javascript异步编程】这个话题中非常重要的,它一度让我感到熟悉又陌生,我熟悉其所有的API并能够在编程中相对熟练地运用,却对其中原理和软件设计思想感到陌生,即便我读了很多源码分析和教程也一度很难理解为什么Promise这样一个普通的类能够实现异步,也曾尝试着去按照Promise/A+规范来编写Promise,但很快便陷入了一种更大的混乱之中。直到我接触到一些软件设计思想以及软件工程方面的知识后,从代码之外的角度来理解一些细节的必要性时,那些陌生才开始一点点消失。
如果你觉得有些新东西很那理解,有很大的原因是因为你和设计者所拥有的基础知识储备不是一个水平的,导致你无法理解设计者写出某段代码时所基于的指导思想,当你无法理解某些看起来很复杂的东西时,笔者的建议是先了解它希望解决的问题,这个问题或许是具体的业务逻辑需求,或许是抽象的软件设计层面的,然后尝试自己想办法去解决它,请永远记得别人是开发者,你也是,你要做的是面向需求,而不仅仅是跟着别人走。即时最终你没能开发出这个模块而去学习源码时,你也会发现面对需求而进行的主动思考对此带来的帮助。
二. 关于Promise的一些困惑Promise的本质,是一个分布式的状态机。而PromiseAPI的本质,就是一个发布订阅模型。
Promise解决了什么问题?
这是一个最基本的问题,Promise是一个有关可靠性和状态管理的编程范式,它通常被认为从代码层面将javascript中著名的回调地狱改变成扁平化的写法,并为指定的业务逻辑打上状态标记,让开发者可以更容易地控制代码执行的流程。但事实上Promise的设计初衷并不是为了实现异步,而且很多开发者并没有意识到,回调并不意味着异步!!!(你传入另一个函数的回调函数有可能被异步执行,也有可能被同步执行)。想更好地理解Promise,就必须把【异步】这个标签从中剥离,而围绕【状态管理】,【可靠性】这些关键词进行展开。
Promise只是一个类,为什么就能够实现异步?
Promise本身的确只是一个普通的类,而且在不依赖ES6的环境中,开发者甚至可以手动实现这样一个类,在没有研究Promise的代码之前,笔者一直主观地认为其内部是通过类似于事件监听的机制来实现异步的,否则程序本身怎么会知道发出的http请求什么时候返回结果。
这个问题是在笔者学习完EventLoop和Generator函数的相关知识后才理解的,其实Promise本身并没有实现异步,javascript语言中的异步都是通过事件循环的机制(《javascript基础修炼(5)——Event Loop(node.js)》)来实现的,简单地说就是说异步事件的响应是会被事件循环不断去主动检测的,当异步动作满足了再次被执行的条件时(比如http请求返回了结果,或者在另一个线程开启的大运算量的逻辑执行完毕后返回了消息),就会被加入调用栈来执行,Promise和Generator只是配合事件循环来进行状态管理和流程控制,它们本身和事件循环的机制是解耦的。
Promise作为构造函数调用而生成实例时到底发生了什么事情?
这里所指的是下面这样的代码:
promise = new Promise(function(resolve, reject){ //.... });面试中经常会问到有关Promise执行次序的问题,很多非常熟悉Promise用法的读者也并没有意识到,实际上传入的匿名函数是会同步执行的。Promise所做的事情,是为当前这个不知道何时能完成的动作打上一些状态的标记,并传入两个用于回收控制权的方法作为参数来启动执行这个匿名函数,通过then方法指定的后续执行逻辑会先缓存起来(这里的描述并不严谨),当这个异步动作完成后调用resolve或者reject方法后,再继续执行事先被缓存起来的流程。
Promise/A+标准看起来很复杂,该如何去实现?
Promise/A+规范的确很复杂,我也不建议你直接就通过这样的方式来了解Promise的实现细节,【规范】意味着严谨性,也表示其中有很多容错的机制,这会极大地妨碍你对Promise核心逻辑的理解,Promise代码最大的复杂性,在于它对于链式调用的支持(如果不需要支持链式调用,你会发现自己几乎不需要思考就可以分分钟撸一个Promise库出来)。笔者的建议是先想办法去解决主要问题,再对照Promise/A+规范去检视自己的代码。
Promise为什么要实现链式调用?