第1章 异步:现在与将来
- 程序中现在运行的部分和将来运行的部分之间的关系就是异步编程的核心。
第2章 回调
- 回调函数会导致回调地狱的问题。
- 回调与我们大脑顺序的思考模式相悖,我们有时需要不停地上下移动视线,以确定函数的正确执行顺序。
- 我们很难使用最原始的回调函数的形式,去囊括所有的可能事件和路径;即使囊括了,我们的代码也会变得非常复杂,以至于无法更新和维护。比如我们对于某个异步操作的结果只指定成功的回调,那么失败之后怎么办呢?如果我们想要再指定一个失败的回调,即分离回调,那么代码的可读性就会大大降低,更不用说回调嵌套的情况了。
- 回调函数的优化:
- 分离回调:既指定成功的回调,也指定失败的回调。
- error-first风格:回调的第一个参数保留,用作错误对象。常见于Node.js。
- 总结回调函数的缺点:
- 第一,大脑对于事情的计划方式是线性的、阻塞的、单线程的语义,但是回调表达异步流程的方式是非线性的、非顺序的,这使得正确推导这样的代码难度很大。难于理解的代码是坏代码,会导致坏bug。我们需要一种更同步、更顺序、更阻塞的的方式来表达异步,就像我们的大脑一样。
- 第二,也是更重要的一点,回调会受到控制反转的影响,因为回调暗中把控制权交给第三方(通常是不受你控制的第三方工具!)来调用你代码中的continuation。这种控制转移导致一系列麻烦的信任问题,比如回调被调用的次数是否会超出预期。
第3章 Promise
- 我们不希望控制被反转,我们希望把控制反转再反转回来。也就是我们希望第三方给我们提供了解其任务何时结束的能力,然后由我们自己的代码来决定下一步做什么。这种范式就被称为Promise。
- 由于Promise封装了依赖于时间的状态——等待底层值的完成或拒绝,所以Promise本身是与时间无关的。因此我们可以等Promise的状态变为已决议之后,再去设置成功或失败的回调。但之前使用回调函数的时候,我们必须在拿到异步结果之前设置成功或失败的回调。
- 另外,一旦Promise决议,它就永远保持在这个状态,可以根据需求多次查看。
- 可以把Promise实例提供给代码中多个独立的部分,在Promise实例完成的时候,它们都可以独立地得到通知。且我们恢复了控制反转,实现了更好的关注点分离。使用Promise实例的地方不需要关注当前任务的具体实现细节。