A.1 序列与抽象设计
理解 asynquence 要从理解一个基本的抽象开始:一个任务的一系列步骤,不管各自是同步的还是异步的,都可以整合起来看成一个序列 (sequence)。换句话说,一个序列代表了一个任务的容器,由完成这个任务的独立(可能是异步)的步骤组成。
序列中的每个步骤在形式上通过一个 Promise(参见第 3 章)控制。也就是说,添加到序列中的每个步骤隐式地创建了一个 Promise 连接到之前序列的尾端。由于 Promise 的语义,序列中每个单个步骤的运行都是异步的,即使是同步完成这个步骤也是如此。
另外,序列通常是从一个步骤到一个步骤线性处理的,也就是说步骤 2 要在步骤 1 完成之后开始,以此类推。
当然,可以从现有的序列分叉 (fork)出新的序列,这意味着主序列到达流程中的这个点上就会发生分叉。也可以通过各种方法合并序列,包括在流程中的特定点上让一个序列包含另一个序列。
序列有点类似于 Promise 链。然而,通过 Promise 链没有“句柄”可以拿到整个链的引用。拿到的 Promise 引用只代表链中当前步骤以及后面的其他步骤。本质上说,你无法持有一个 Promise 链的引用,除非你拿到链中第一个 Promise 的引用。
很多情况下,持有到整个序列的引用是非常有用的。其中最重要的就是序列的停止或取消。就像我们在第 3 章扩展讨论过的,Promise 本身永远不应该可以被取消,因为这违背了一个基本的设计规则:外部不可变性。
但对序列来说,并没有这样的不可变设计原则,主要是因为序列不会被作为需要不可变值语义的未来值容器来传递。因此,序列是处理停止或取消行为的正确抽象层级。asynquence 序列可以在任何时间被 abort() ,序列会在这个时间点停止,不会因为任何理由继续进行下去。
之所以选择在 Promise 之上建立序列抽象用于流程控制的目的,还有很多别的理由。
第 一,Promise 链接更多是一个手工过程。一旦开始在大范围的程序内创建和链接 Promise,事情就可能会变得十分乏味。这种麻烦可能会极大阻碍开发者在 Promise 本来十分适用的地方使用 Promise。
抽象的目的是减少重复样板代码和避免乏味,所以序列抽象是针对这个问题的一个很好的解决方案。通过 Promise,你的关注点放在各个步骤上,几乎没有假定链的继续。而如果使用序列的话,情况则正好相反:会假定序列持续,会有更多的步骤无限地附加上来。
当考虑到更高阶的 Promise 模式时(在 race([..]) 和 all([..]) 之上),这种抽象复杂性的降低就格外强大了。
举例来说,在序列当中,你可能想要表达一个在概念上类似 try..catch 的步骤,这个步骤总是返回成功,要么是想要的主功能成功决议,要么是一个标识被捕获错误的非错误信号。或者,你可能想要表达一个类似 retry/until 的循环,其中会持续重复试验同样的步骤直到成功为止。
如果只使用 Promise 原语表达的话,这些种类的抽象工作量可并不小,在现有的 Promise 链当中实现也并不优美。但是,如果把你的思路抽象为序列,并把步骤当作对 Promise 的封装,那么这样的步骤封装就可以隐藏这些细节,节省你的精力,从而让你以最合理的方式考虑流程控制,不需要为细节所困。
第二,可能也是最重要的一点,以序列中的步骤这样的视角来考量异步流程控制,这样就可以把每个单独步骤涉及的异步类型等细节抽象出去。在此之下,总是由 Promise 来控制着这个步骤,但是表面上,这个步骤看起来要么类似 continuation 回调(最简单的默认情况),要么类似真正的 Promise,要么就类似完整运行的生成器,要么……希望你已经理解了我的意思。
第三,序列很容易被改造,以适应不同的思考模式,比如基于事件、基于流、基于响应的编码。asynquence 提供了一个模式,我称之为响应序列 (reactive sequence,后面会介绍),是 RxJS(Reactive 扩展)中 reactive observable 思想的一个变体。它利用重复的事件每次启动一个新的序列实例。Promise 只有一次,所以单独使用 Promise 对于表达重复的异步是很笨拙的。
另外,有一种思路在一个被我称为可迭代序列 的模式中反转了决议和控制功能。不再是每个单独的步骤在内部控制自己的完成(于是有序列前进),事实上,这个序列被反转了,前进控制是通过外部的迭代器,并且可迭代序列中的每个步骤只响应 next(..) 迭代器控制。
本附录在后面会介绍这些不同的变体,所以不必担心刚才的讨论过于简略。
需要记住的是,对复杂异步来说,比起只用 Promise(Promise 链)或只用生成器,序列是更强大更合理的抽象。asynquence 的设计目标就是在合适的层级表达这个抽象,使异步编程更容易理解、更有乐趣。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论