从 SPA 到 PWA:Web App的下一站在哪?

从 SPA 到 PWA:Web App的下一站在哪?

作者|杨珺(百度前端资深研发工程师)

从 AJAX(Asynchronous JavaScript + XML,异步 JavaScript 和 XML)开始, 尤其是 AngularJS 推出之后,SPA(Single Page App,单页应用)已经成为前端 App 的必选方案。

SPA 可以在客户端提供完整的路由、页面渲染、甚至一部分数据处理; 这往往需要一个比 jQuery 时代更重的 JavaScript 框架,来实现这些原本发生在后端的逻辑。

多数框架如 React、Vue 还会内置组件化机制来帮助开发者组织代码, 它们甚至进化到专门负责视图组件的程度,路由和数据交由各种插件来处理, 比如 vuex、Redux、Vue Router 等等。这些工具已经相当先进和完整,提供了路由方案、服务器端渲染方案、前端状态管理方案。

但 SPA 的本质还是浏览器端 App,底层技术仍然依赖 history API、defineProperty、AJAX。 这些 API 的能力和完备性,决定了 SPA 能达到的用户体验和上层架构设计。

也正是这些底层 API 的不足和缺陷使得 SPA 很难企及原始 Web 的架构优势。 比如在内容可访问性(Accessibility)、服务的独立部署和演化(Independent Deployment) 等方面远不及十年前搭建的同类站点。

同时还在不同程度上破坏了 HTTP、URL、HTML 的语义, 这些缺陷使我们需要花费大量精力去修复日志统计、性能优化、首屏渲染、静态分析和测试等环节。而陷阱在于决策使用 SPA 方案时不一定能有足够的远见看到这些问题对架构带来的深远影响。

与此同时 Web 标准也在持续迭代,诸如 Web Bluetooth、Push API、Web of Things、Service Worker 的标准已经在主流浏览器(尤其考虑国内 webkit 内核的普及程度)有不同程度的支持。 尤其是 PWA 概念的提出,给出了一种在不破坏 Web 架构的前提下实现流畅用户体验的方式。

本文就 SPA 架构的一些不足展开讨论,并探讨 PWA 方案(这里说是方案,其实更是一种技术方向的选择)的价值和私有平台的最佳演化方式。

我们想要怎样的 Web App?

Web 页面尤其是动态 Web 页面和 Web App 的区别非常模糊, 但为了更清晰地讨论 SPA、PWA 这些技术方案,还是先来定性地分析一下 Web App 背后的产品需求:

  1. 平滑的、不被打断的交互体验。如果交互过程中,页面重新加载而丢失状态、网络原因使得页面无法显示,这样用户体验就会被打断,就不够 App。
  2. 与设备相适应的布局。例如在移动浏览器中展示 PC 页面的完整布局,就会使用户需要缩放和拖动才能查看信息,就不是 App 的体验。
  3. 快速的呈现和响应。进入每一页都需要漫长的等待,或者用户操作后得不到立即反馈,可能是 Web 页面常见的问题。
  4. 符合移动端的交互习惯。移动端特有的硬件使其 Native API 更加丰富,例如蓝牙、二维码、相机、支付、手势滑动、手势缩放、触感反馈等。

以上是笔者对 Web App 需求的理解(欢迎留下评论),下文基于此展开讨论。

Web 架构的优势

值得思考的是,即使 Web 页面与我们对移动 App 的需求相差甚远, Web 技术仍然是当前移动 App 的架构中必备的组成部分。 我们依赖 Web 技术的地方正是 Web 架构的优势:

  1. 可链接。Web 在技术分类上属于分布式文档,这些文档通过 URL 相互链接。无论是单个网站内的不同页面还是跨网站的页面之间,都可以直接打开而无需下载安装。这里要强调一个隐含的功能:Deep Linking,即从一个 App 跳转进入另一个 App 内的指定页面,甚至还可以定位到特定的浏览位置。
  2. 可访问。HTML 是 Web 的基石之一,一方面提供了内容和样式的分离,使得机器和人都可以阅读也便于开发更复杂的样式和交互;另一方面统一的标记语言有更好的可访问性,这是其他平台很难建设的,比如可以选择和复制,盲人可以启用屏幕阅读器,甚至可以找命令行中查看一个 Web 页面。
  3. 零门槛。你不需要任何许可或付费就可以参与开发和提供 Web 服务。这意味着同时存在无数种方式来开发一个网站,在一定程度上促成了 Web 技术的繁荣。
  4. 独立部署。不同的 Web 服务之间,甚至同一 Web 服务的各部分,都可以独立地部署和演化。新旧网站可以同时运行在这一平台上,这一点也是 HTML5 标准的迭代原则。
  5. 健壮性。Web 页面拥有分布式系统特有的健壮性。Web 页面和它所依赖的图片、视频、脚本、样式等资源没有硬性依赖:一方面部分资源挂掉页面的其他功能仍然可用;另一方面 Web App 可以一边下载一边执行,这是其他平台很难具有的健壮性。

在 SPA 大行其道之后广泛讨论的兼容性、响应式设计、可访问性(或称无障碍)、页面性能等问题, 本来都是 Web 体系结构的优势,这是一个略带调侃的示例页面:https://motherfuckingwebsite.com

这个只有 81 行的网页,不仅传递了相当多的内容,而且它在兼容性、响应式设计、可访问性、页面性能方面都表现优异。

重要的是这个页面使用的技术都来自 Web 早期,换句话说这些非功能需求正是 Web 与生俱来的优势。既然我们正在费力解决的这些问题不来自于 Web 本身,那么这些问题到底来自哪里? 是重 JavaScript 框架的问题,还是组件化方案的问题,还是掉进开发者体验陷阱?

SPA 方案的困难

本文不去讨论某个具体的 SPA 框架的成败或优缺点,只讨论采用 SPA 方案来实现我们想要的 Web App 存在哪些困难,以及 SPA 方案对既有 Web 页面的影响。 下面列举 SPA 方案对架构产生的一些比较重要的影响,从可链接性(URL)、可访问性,服务的独立性等方面具体分析。

SPA 是一组高度耦合的页面(页面耦合)

SPA 方案要求 App 内所有页面位于同一服务实例上, 也就是说处理 SPA 页面请求的每个实例都必须拥有 App 内所有页面的信息, 这一信息通常是页面组件的声明。

这是因为 SPA 要求页面切换不发生浏览器跳转。设想操作流程『打开页面 A -> pushState 到页面 B -> 刷新 -> 返回』,这时浏览器不会重新加载 A,而只是触发 popstate 事件给 B。 因此对于任意页面 A,点出到的任意页面 B,B 页面反过来都需要知道页面 A 的信息,当然页面 A 也知道页面 B 的信息,因此任意两个有跳转关系的页面,都需要相互了解对方的信息,或引用对方组件。

这样相互耦合的一组页面,就构成了一个 SPA 方案的 Web App。 这样的 App 内所有页面都不再能够『独立部署』,因此也不能独立迭代演化。

这往往意味着它们的开发调试、前端编译、部署过程都是耦合在一起的, 这些都是 SPA 方案带来的成本:

  • 开发依赖:因为要能够打开一个页面必须引用对应的组件,这些组件在开发和调试阶段一定需要绑在一起。如果两个页面涉及到业务会跨团队,无疑会增加很多成本。
  • 编译依赖:考虑使用 MD5 戳的编译方法,相互引用的一组文件必须一起编译上线,这会降低协作效率因为它们本属于不同的业务或团队。当然也可以不使用 MD5 戳并分别上线,动态调整引用关系,这样的问题在于无法平衡 HTTP 缓存和快速生效的矛盾。

此外,由于浏览器的同源策略,一个 Web App 被限制共享一个域名。 否则在富交互的场景下跨域将会是一个非常复杂的问题, 当然如果你愿意使用 JSONP 这么不安全的接口另当别论。

强组件化容易陷入技术竖井(技术封闭)

SPA 方案伴随着强组件化方案,容易陷入封闭的技术竖井。 换句话说就是容易一条路走到黑,失去 Web 应有的架构优势。 这是因为异步页面拥有异步的天性。 浏览器重新渲染一个页面时, 全局变量、定时器、事件监听器都会初始化为全新的,这是『刷新』的含义。 而异步页面却不然:

  • 异步页面间,全局变量、定时器是共享的,没有托管很容易乱掉。
  • 异步页面的


分享到:


相關文章: