通过回调表达程序异步和管理并发主要有两个主要缺陷:缺乏顺序性和可信任性。
- 顺序性就是回调地狱问题,多层嵌套的回调导致可读性非常差
- 可信任性,传统的实现,需要我们将封装好的回调函数,传到第三方去,由第三方控制如何使用回调。promise 只负责任务结束之后的通知,后续的操作由自己代码决定
我们首先想要解决的是控制反转问题,其中,信任很脆弱,也很容易失去。
回忆一下,我们用回调函数来封装程序中的 continuation,然后把回调交给第三方(甚至可能是外部代码),接着期待其能够调用回调,实现正确的功能。
通过这种形式,我们要表达的意思是:“这是将来要做的事情,要在当前的步骤完成之后发生。”
但是,如果我们能够把控制反转再反转回来,会怎样呢?如果我们不把自己程序的 continuation 传给第三方,而是希望第三方给我们提供了解其任务何时结束的能力,然后由我们自己的代码来决定下一步做什么,那将会怎样呢?
这种范式就称为 Promise。
回调的信任问题主要有几个方面
调用回调过早
对一个 Promise 调用 then(..) 的时候,即使这个 Promise 已经决议,提供给 then(..) 的回调也总会被异步调用
调用回调过晚
和前面一点类似,Promise 创建对象调用 resolve(..) 或 reject(..) 时,这个 Promise 的 then(..) 注册的观察回调就会被自动调度。可以确信,这些被调度的回调在下一个异步事件点上一定会被触发
调用回调次数过多或过少
“过少”的情况就是调用 0 次,Promise 提供了竞态的高级抽象机制,即 Promise.race 。“过多”的情况很容易解释。Promise 的定义方式使得它只能被决议一次。
未能传递所需要的环境和参数
Promise 至多只能有一个决议值(完成或拒绝),如果你没有用任何值显式决议,那么这个值就是 undefined