Promise/A+ 到底应该怎么用

也许是太久没有关注 Javascript,直到最近发现很多地方都出现 Promise(/A+) 这个词,才意识到我似乎错过了什么。不仅是 Javascript,连 PHP 的 Guzzle 库都有 Promise。

意识到这可能是一个我必须知道的知识点,我打开 MDN 查询了 Promise 的定义和用法,嗯,定义和例子我都看懂了,但依旧扫除不了我对 Promise 存在的意义的蒙逼感…… 到底这玩意儿好在什么地方啊?

还好有谷歌对智商的加持,我大概搞明白 Promise 是解决什么问题的了,看了网上那么多不明觉厉的文章,最后还是自己的理解比较接地气。

要说 Promise 的意义,有个话题是绕不过去的,那就是异步代码执行。

不过说这个话题之前我们先用同步执行的代码举一个超级简单的栗子:假如我是厨师要做鸡汤,做汤的过程可以用以下伪代码表示:

栗子虽然糙但是逻辑没毛病。看起来流程也是很简洁。

然而,假如厨师的几个处理鸡的方法都是异步的,那代码就会变成这鸡毛样:

大家应该都看出差别,因为异步调用必须采用『回调函数』这种方式来处理异步代码的执行结果,如果每一步异步处理又是依赖于前一次处理的结果,就会发现代码不断在回调函数里缩进以至于达成所谓『回调地狱』的成就(想想我们的 Ajax 异步调用)。

大家都不爱『地狱』如同大家都不爱在 if/else 里嵌套又一个 if/else 一样,所以 Promise 就这么应运而生了。

关于 Promise 的定义和各种方法的定义这里我就不再说了,MDN 上说的很详细。这里我只说 Promise 的用法。因为异步代码无法直接用 return 来给方法返回结果,所以只能用回调函数的方式。但如果把异步调用的代码返回 Promise,那么写法就会变成类似这样:

这样看是不是感觉又利落许多?

异步调用除了返回值的获取不如同步调用那么方便之外,异常也是类似,所以除了 then 方法之外还有获取异常的 catch 方法:

说了 Promise 的目的,再来说说 Promise 的用法。初看 Promise 的 API,说实话的确是容易绕晕。加入让我们自己实现 Promise,我们可以先简化一下,只实现 then 的 onFulfilled

再结合调用的代码一起看

首先 Promise 的构造函数里输入的参数是一个匿名函数,而且是一个处理异步调用的匿名函数,而且此匿名函数接受一个参数,正好此参数又是另外一个匿名函数(我怎么感觉从回调函数地狱跳到到了匿名调用的坑了……),而这『匿名函数里的匿名函数』正是 Promise 对象的一个私有函数 fulfill,而这个私有函数,正是等当异步函数得到最终返回结果时,处理此结果的函数。

不过处理结果的函数不应该是 then 里传入的匿名函数么?其实 fulfill 函数内部调用的正是 then 传入的匿名函数。听起来像是 Promise 在创建好后执行异步匿名函数 A,A 成功后会调用 fulfill 函数,fulfill 函数会调用 then 方法传入的匿名函数 B,中间好像多了 fulfill 函数这个步骤,难道不能跳过 fulfill 直接让 A 函数调用 B 函数么?的确不能。因为匿名函数 A 要求传入接受异步执行结果的匿名函数,而 Promise 对象创建的时候真正的结果处理匿名函数 B 还没有通过 then 方法注册到 Promise 对象里呢,只能事先在 Promise 类里定义好 fulfill 方法,将 fulfill 传给 A 函数,等真正异步代码执行完毕的时候,因为主线程上 B 函数也已经注册好了,当 A 调用 fulfill 的时候,fulfill 再委托真正的结果处理函数 B 来执行结果处理。

wx pay

CC BY-NC-ND 4.0 Promise/A+ 到底应该怎么用 by Chrisyue's Blog is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

发表评论

电子邮件地址不会被公开。

CAPTCHA
Change the CAPTCHA codeSpeak the CAPTCHA code