AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

备受 Vue、Angular 和 React 青睐的 Signals 演进史

  • 2023-04-10
    北京
  • 本文字数:3519 字

    阅读完需:约 12 分钟

备受Vue、Angular和React青睐的Signals演进史

最近,在前端领域,围绕着“Signals”这个词,有一些热烈的讨论。不管是Preact还是Angular,似乎都在讨论该话题。

 

但它们并不是什么新东西。如果我们将其追溯到上个世纪 60 年代的研究,那么这就更算不上新鲜的事物了。它的基础采用了与第一个电子表格和硬件描述语言(如 Verilog 和 VHDL)相同的模型。

 

即便是在 JavaScript 中,从声明式 JavaScript 框架诞生开始,我们就拥有这种理念了。随着时间的推移,它们有了不同的名字,并且在这些年里不断流行了起来。现在,它又重新出现了,这是一个很好的时机,我们可以对它是什么以及为何需要它进行更多的介绍。

 

免责声明:我是 SolidJS 的作者。本文从我的角度介绍了演进的过程。尽管文中没有提及,但是Elm SignalsEmber的计算属性Meteor都是很值得称道的。

 

如果你还不清楚 Signals 是什么以及它是如何运行的,请参阅我的这篇对细粒度反应性(Fine-Grained Reactivity)的介绍。

起初的蛮荒时代

 

有时候,我们会惊讶地发现,很多参与者在完全相同的时间形成了类似的方案。在声明式 JavaScript 框架的起步阶段,有三个方案在三个月内陆续发布,它们分别是Knockout.js(2010 年 7 月)、Backbone.js(2010 年 10 月)和Angular.js(2010 年 10 月)。

 

Angular 的脏值检查、Backbone 的模型驱动重渲染以及 Knockout 的细粒度更新,虽然它们彼此间有些差异,但是最终都成为了我们今天管理 state 和更新 DOM 的基础。

 

Knockout.js 对本文的主题特别重要,因为它们的细粒度更新是建立在所谓的“Signals”的基础之上的。他们最初引入了两个概念,分别为 observable(状态)和 computed(副作用),但是在接下来的几年中,他们在前端语言中引入了第三个概念 pureComputed(衍生状态)。

 

const count = ko.observable(0);

const doubleCount = ko.pureComputed(() => count() * 2);

// 每当doubleCount更新时,打印日志记录ko.computed(() => console.log(doubleCount()))
复制代码

狂野时代



在这个时代,服务器端开发的 MVC 和过去几年从 jQuery 中学到的模式进行了融合,形成了新的模式。其中,最常见的一个模式叫做数据绑定,Angular.js 和 Knockout.js 都具有该模式,不过实现方式略有不同。

 

数据绑定的概念是,state(状态)应该被关联(attached)到 view tree(视图树)的一个特定部分上。借助这种方式,能够实现的一种强大功能叫做双向绑定。所以,我们可以让状态更新 DOM,反过来,DOM 事件会自动更新状态,所有的这一切均是以一种简单的声明方式实现的。

 

但是,滥用这种力量最终会作茧自缚。我们构建应用的时候,对其缺乏足够深入的了解。在 Angular 中,如果不知道什么内容发生变化,就会对整个树进行脏值检查,而向上传播会导致它多次发生。在 Knockout 中,很难跟踪变化的路径,因为你会在 DOM 上走来走去,出现循环也是司空见惯的。

 

React出现的时候,我们已经准备好逃离这一切了,对我个人来说,是Jing Chen的演讲,让我稳住了阵脚。

 

00:00 / 00:00
    1.0x
    • 3.0x
    • 2.5x
    • 2.0x
    • 1.5x
    • 1.25x
    • 1.0x
    • 0.75x
    • 0.5x
    网页全屏
    全屏
    00:00


    自由时刻



    接下来,就是对 React 的采用。有些人依然喜欢反应式模型,因为 React 对状态管理没有自己的偏好,所以完全可以将两者结合起来。

     

    Mobservable(2015)就是这样的方案。但是,相对于与 React 的集成,它还带来了一些新的内容。它强调一致性和顺畅(glitch-free)的传播。也就是说,对于任何给定的变更,系统的每个部分仅运行一次,而且以适当的顺序同步运行。

     

    为了实现这一点,它使用了一种推-拉(push-pull)混合的系统来替换先前方案中基于推送的反应性。变更的通知会被推送出去,但是衍生状态的执行会推迟到读取它的地方。

     


    为了更好地理解 Mobservable 的原始方式,请参阅 Michel Westrate 的“Becoming Fully Reactive: An in Depth Explanation of Mobservable”一文。

     

    虽然在很大程度上,这个细节会被 React 重新渲染读取变更的组件所掩盖,但是,这是使系统实现可调试和一致性的关键步骤。在接下来的几年里,随着算法的不断完善,我们会看到一种趋势,那就是更多基于拉取的语义

     

    征服泄露的观察者



    细粒度反应性是四人组(Gang of Four)观察者模式的变种。虽然观察者模式是一个强大的同步模式,但是它也有一个典型的问题。一个 Signal 会保持对所有订阅者的强引用,所以长期存活的 Signal 会保留所有的订阅,除非进行手动处置。

     

    这种记录方式在大量使用时会变得很复杂,尤其是在涉及嵌套的时候。在处理分支逻辑和树的时候嵌套很常见的,就像在构建 UI 视图时的那样。

     

    有一个鲜为人知的库,叫做S.js(2013)提供了答案。S 是独立于其他大多数解决方案而开发的,它更直接地以数字电路作为模型,所有的状态变化都在时钟周期内进行。S 将其状态基元称为“Signals”。尽管它不是第一个使用该名字的,但它是我们今天使用该术语的起源。

     

    更为重要的是,它引入了反应式所有权的概念。所有者会收集所有的子反应式作用域,并在所有者处置(disposal)自身或重新执行时,管理子反应式作用域的处置。反应式图会从一个根所有者开始,然后每个节点均作为它所拥有的后代。这个所有者模式不仅对处置过程很有用处,而且在反应式图中,建立了一种提供者/消费者(Provider/Consumer)上下文的机制。

     

    调度



    Vue(2014)也为我们今天的发展做出了巨大的贡献。除了在优化一致一致性方面与 MobX 的节奏保持一致之外,Vue 从一开始就将细粒度反应性作为其核心。

     

    虽然 Vue 和 React 都使用了虚拟 DOM,但是 Vue 的反应性得到了最好的支持,这意味着它是与框架一起研发的,首先是作为内部机制,为其 Options API 提供支持,在过去的几年中,它成为了 Composition API(2020)的前沿和核心。

     

    Vue 将推送/拉取向前推进了一步,能够调度任务何时会完成。默认情况下,Vue 会收集所有的变更,但是下一个微任务在处理作用(effect)队列之前不会处理它们。

     

    然而,这种调度也可以用来做其他的事情,比如 keep-alive 和 Suspense。甚至像并发渲染这样的功能也可以用这种方式来实现,从而充分体现了如何同时利用基于推送和拉取的方式能够达成的最佳效果。

     

    编译

     

    在 2019 年,Svelte 3向我们展示了利用编译器能够完成多少事情。实际上,他们将反应性完全编译掉了。在这过程中,也会有一些权衡,Svelte 向我们展示了编译器如何抹平人类工程学方面的欠缺。这将会成为一种趋势。

     

    反应式语言(如状态、衍生状态、作用)不仅向我们描述了用户界面等同步系统所需的所有内容,而且它是可分析的。我们可以精确地知道都发生了哪些变更以及它们发生在什么地方。可追溯性的潜力是很深远的。

     

    来自Preact团队的 Marvin Hagemeister在Twitter这样说到,“我认为这是基于 Signals 的方式优于钩子(hook)的主要原因之一。它能够使我们添加更多的调试洞察力,这是钩子所无法实现的,比如准确地显示一个状态发生变更的原因。”

     

    如果能够在编译时知道这一切,我们就可以交付更少的 JavaScript 代码。对于代码的加载,我们会有更高的自由度。这就是QwikMarko的可恢复性的基础。

     

    面向未来的 Signals

     

    Angular 团队的成员 Pawel Kozlowski 则认为

     

    “Signals 是新的 VDOM。

     

    人们对它的兴趣正在爆发:很多人正在尝试一些新东西。这将使我们能够探索该领域,尝试不同的策略,对其增进了解和优化。

     

    虽然现在不知道最终结果是什么,但是这种集体探索是很好的!”

     

    鉴于这项技术已经非常古老,说还有很多东西需要探索,这可能会令人感到惊讶。但是,这里的原因在于,它是一种对解决方案进行建模的方式,而不是一种具体的方案。它所提供的是一种描述状态同步的语言,与要让它执行的副作用完全无关。

     

    因此,它能够被 Vue、Solid、Preact、Qwik 和 Angular 采用似乎并不足为奇。我们已经看到它进入了 Rust 的 Leptos 和 Sycamore,表明 DOM 上的 WASM不一定会慢。React 甚至考虑在底层使用它。

     

    来自 React 核心团队的 Andrew Clark表示

     

    “我们可能会在 React 中添加一个类似 Signals 的基元,但我并不认为这是一个编写 UI 代码的好方法。它对性能来说是很好的。但我更喜欢 React 的模式,在这种模式下,你每次都会假装重新创建所有的内容。我们的计划是使用一个编译器来实现与之相当的性能”。

     

    也许这是一种合适的方式,因为 React 的虚拟 DOM 始终只是一个实现细节。

     

    Signals 和反应性语言似乎是一个交汇点。但是,这在 JavaScript 诞生之初却并不那么明显。也许这是因为 JavaScript 并不是最好的语言。我甚至可以说,长期以来,我们在前端框架设计中感受到的很多痛苦都是语言本身的问题。

     

    无论这一切的结局如何,到目前为止,都是一次相当不错的旅程。有这么多人关注 Signals,我迫不及待地想知道我们的下一步会是什么。

     

    原文链接:

    https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob

    相关阅读:

    手写一个 react,看透 react 运行机制

    看透 react 源码之感受 react 的进化

    2023 重学 Angular

    初识 VUE 响应式原理

    2023-04-10 12:445449

    评论

    发布
    暂无评论
    发现更多内容

    几天不写React,已经看不懂语法了

    伤感汤姆布利柏

    加速布局,用友为国产化替代保驾护航!

    用友BIP

    国产替代

    业务创新的利器:探索Flutter与小程序容器的融合应用

    FinClip

    手把手教学构建农业知识图谱:农业领域的信息检索+智能问答,命名实体识别,关系抽取,实体关系查询

    汀丶人工智能

    人工智能 深度学习 nlp 知识图谱 智能问答

    飞桨和硬件伙伴们在WAIC 2023!

    飞桨PaddlePaddle

    人工智能 百度 paddle 飞桨 百度飞桨

    手把手教学构建证券知识图谱/知识库(含码源):网页获取信息、设计图谱、Cypher查询、Neo4j关系可视化展示

    汀丶人工智能

    人工智能 自然语言处理 nlp 知识图谱

    PoseiSwap 更新第二期空投,持有 Zepoch 节点数量将决定空投回报

    西柚子

    智能电视APP鲜时光,如何应用AB测试打造极致的用户观看体验?

    字节跳动数据平台

    Pytorch: 数据读取机制Dataloader与Dataset

    timerring

    人工智能

    新兴技术与禅坐 | 聊聊经验 | 社区征文

    写程序的小王叔叔

    经验分享 年中技术盘点

    IT运维的福音!WeOps综合服务让运维更简单

    嘉为蓝鲸

    运维 IT weops

    PoseiSwap 更新第二期空投,持有 Zepoch 节点数量将决定空投回报

    鳄鱼视界

    如何优化Flutter的性能?

    没有用户名丶

    户外led显示屏常见规格有哪些

    Dylan

    广告 屏幕亮度 像素 LED显示屏 户外LED显示屏

    Git操作不规范,战友提刀来相见!

    树上有只程序猿

    深度剖析之由浅入深揭秘JavaScript类型转换(最全总结篇)

    Immerse

    JavaScript 类型转换 隐式转换 类型 强制类型转换

    Kurator v0.4.0版本更新4大内容,满足多云环境的复杂需求

    华为云开发者联盟

    云原生 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

    用友iuap亮相全球数字经济大会助力企业升级数智化底座

    用友BIP

    数智底座

    万字血书React—走近React

    不在线第一只蜗牛

    React 教程分享

    基于知识图谱的《红楼梦》人物关系可视化及问答系统(含码源):命名实体识别、关系识别、LTP简单教学

    汀丶人工智能

    人工智能 深度学习 nlp 知识图谱 智能问答

    中国大模型的落地DNA,写在这个双螺旋结构里

    脑极体

    AI

    企业内容管理升级 3.0:构建生态协同,助力合规成长

    风来兮

    软件 电子档案 OCR 合规 #人工智能

    谈谈我这两年的前端开发经验

    树上有只程序猿

    INFINI Labs 产品更新 | Easysearch 新增 kNN 搜索功能、Console 支持 LDAP 认证登录等

    极限实验室

    console Gateway 产品更新 easysearch 极限科技

    区块链生态架构 | 社区征文

    TiAmo

    区块链 Baas 年中技术盘点

    深入解析Redis的LRU与LFU算法实现

    vivo互联网技术

    redis LRU LFU

    王海峰最新发声!

    飞桨PaddlePaddle

    人工智能 百度 paddle 飞桨 百度飞桨

    科兴未来|第二届T-MAX“科创太仓”国际创新创业--先进材料专场赛

    科兴未来News

    备受Vue、Angular和React青睐的Signals演进史_大前端_Ryan Carniato_InfoQ精选文章