客户端应用程序的全局可变状态

Global mutable state of client-side applications

本文关键字:状态 全局 应用程序 客户端      更新时间:2023-09-26

这可能是一个非常普通(可能很天真)的问题。

据我所知,"客户端"应用程序(即在浏览器中运行的应用程序)的编程模型意味着有一个共享的可变对象——网页的DOM——要由javascript程序更新Naive我看到的应用程序由几十个JS回调组成,这些回调更新了一个大型共享DOM

这是正确的吗?现代JS框架是如何管理它的?他们如何实现数据隐藏

除非您依赖window.open、iframes,或者允许您的应用程序跨越多个相互通信的窗口/选项卡(可能通过postMessage进行cmunication),否则您没有其他选择来操作同一文档:只有一个文档。

然而,并不是因为一个文档被操纵,文档本身就不能被划分为多个封装的协作模块。Nicholas Zakas在他的Scalable JavaScript Application Architecture演示中很好地展示了这个概念。

模块应该在其操作所依据的文档中有一个非常严格的部分。这是他们自己的小沙箱,他们不应该进入其他模块的沙箱。如果他们需要沟通,他们会以一种非常解耦的方式(例如通过中介)进行沟通。

今天的大多数框架都依赖于模型-视图-控制器(MVC)的客户端变体(通常称为MV*/MVW)来实现这一目标。我不会在这里详细介绍,但主要目标是将数据与视图(表示)解耦,并经常将视图与在Controller对象中完成的用户操作的处理解耦。

直到最近,还没有真正的方法来强制封装。例如,不可能阻止jQuery插件外部的一些代码修改该插件生成的DOM结构。我们不得不依靠程序员的专业精神来确保他们不会触及插件的内部。

现在,有了引入ShadowDOM等新概念的Web组件规范,就可以进行真正的封装。不幸的是,该规范尚未在浏览器中实现,但幸运的是,有谷歌的Polymer项目,它可以被视为一个Web组件填充程序。

现代JS框架使用Javascript语言来:

  1. 注册对DOM事件的兴趣
  2. 响应DOM事件:
    • 直接通过创建或更改对象状态,或者
    • 通过发出远程"ajax"请求并使用响应更新其状态
  3. 通过(选择性地)更新DOM来反映其修改后的部分或全部状态

这就是现代客户端应用程序的基本运行循环。

当然,有很多框架可以用来实现这一点,每一个框架都以不同的方式实现基本范式。像jQuery这样的一些框架倾向于采用"DOM就是真理"的方法,并将其状态数据挂在DOM上,而像Ember.js这样的其他框架则相反,采用"模型就是真理"方法,并在DOM之外管理状态。

许多框架中使用的一种常见模式是MV*,即Model/View/Something。框架将具有某种管理状态的模型、某种视图/模板层,以及控制/协调/编排应用程序的其他层。这可能是临时的,也可能是不存在的(即数百个DOM事件回调),或者是非常结构化和复杂的,具体取决于框架。

有一点值得注意,因为有一些稍微有误导性的评论,那就是这些框架中的视图层并不等同于DOM。最终在DOM中的实际上是呈现视图的输出,即DOM是视图的呈现