返回介绍

第一部分 类型和语法

第二部分 异步和性能

A.1 序列与抽象设计

发布于 2023-05-24 16:38:21 字数 2225 浏览 0 评论 0 收藏 0

理解 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文