SPA应用的一种替代 Phoenix LiveView

1,268 阅读4分钟

1、简介

由Phoenix官方团队在2019年3月正式推出的一个后端渲染框架,主要目的是让开发者用最小的成本去开发出具有实时交互体验的web应用。

LiveView 通过服务器呈现的 HTML 提供丰富的实时用户体验。

一旦状态发生变化,LiveView 将重新渲染其 HTML 模板的相关部分并将其推送到浏览器,浏览器会以最有效的方式进行自我更新。这意味着开发人员可以像编写任何其他服务器渲染的 HTML 一样编写 LiveView 模板,而 LiveView 则负责跟踪更改并将相关差异发送到浏览器。

2、背景

(1) 常见实时的用户交互体验:

① 搜索框自动补全

② 表单实时验证

③ 实时聊天

(2) 已有的解决方案:

① SPA(Single Page Application)

应用:Google Docs 和 Figma (基于浏览器的界面设计协作工具)

优势:今天实现最为复杂的交互、动画效果,可以离线使用

劣势:前后端分离,开发效率低下,对SEO不友好

② AJAX应用(服务端API+JQUERY)

例子:Ruby on Rails, Phoenix(Without LiveView)

应用:Gmail

优势:初期代码复杂度相对较低,开发效率高,对SEO友好

劣势:实时性弱,数据更新往往通过刷新界面来获取,请求速度慢(每次刷新重新获取数据)

③ 介于两者之间

例子:Turbolinks,Stimulus

应用:Basecamp

开发效率和实时性均在单界面应用和AJAX应用之间

总结:

image.png

3、Phoenix LiveView 原理

image.png

① 浏览器通过WebSockets与LiveViewChannel进行连接,发送phx 前缀的事件信息发送个Channel

② Channel中定义的GenServer 调用 在live module定义了handle_event/callback 对数据进行更新

③ 数据更新之后,返回一个tuple把新数据返回给channel

④ 调用LiveViewDiff这个模块进行diff操作,查看哪些更新,哪些需要返回给前端

⑤ 返回部分更新内容给channel

⑥ channel把diff更新或者重定向 push到前端浏览器

⑦ 浏览器通过morphdom模块对前端进行 diff的patch操作并且触发JS hooks

4、LIveView优势

(1)满足大部分实时交互需求

① CRUD操作实时更新 => Twitter Timeline

② 服务端主动推送数据更新至客户端 => Phoenix Live Dashboard

③ 提供 JavaScript Hook functions 进行定制 => Infinite Scroll

(2)高效的开发体验

代码量少,不用考虑如何设计后端API的请求路径,返回数据的结构,如何追踪数据变化,如何通知客户端的数据更新,如何在前端在接受API解析更新dom这些非核心部分。

livevie实现了数据状态变化的管理,在开发中只需关注核心的部分。

image.png

image.png

(3)极致的性能

① diff机制高效,且仍有优化空间

​ 渲染时会区分静态内容与动态内容、状态发生时,静态不变,动态变化

​ 只传输动态中变化的数据diff、进一步减少payload大小

​ 目前是JSON ->后面会支持 Erlang Term Format(ETF) 原生格式支持,服务端负载能力提升和减小数据包大小

② 纵向扩展有Phoenix Channel做保障

​ 在一台40核,128GB内存的服务器上可以支撑到200W分websockets连接同时进行

③ 横向扩展有Erlang OTP做保障

​ 连接多台机器组成集群

(4)SEO友好

①首次渲染默认返回完整的HTML response,无论浏览器还是爬虫都能拿到完整数据

② HTML渲染结束之后再简历WebSocket连接启动LiveView生命周期,保证浏览器数据的正常更新

5、LiveView劣势

主要源于WebSocket的依赖

① 无法在离线状态下正常使用 => 复杂的本地应用(例:Figma)

② 用户体验容易受延迟影响 => 游戏,动画效果

  • 动画 - 首先不需要服务器的动画、菜单和一般 UI 事件不适合 LiveView。这些可以在没有 LiveView 的情况下以多种方式实现,例如使用 CSS 和 CSS 转换、使用 LiveView 钩子,甚至与为此目的设计的 UI 工具包集成,例如 Bootstrap、Alpine.JS 等。

官方团队尝试解决,缓存,开场动画等完善延迟效果,离线状态下进行缓存。