SPA 是什么? 有什么用? 能吃吗?
经常上网冲浪的同学应该听说过 SPA 这个词, SPA(single-page application, 单页应用程序)是一种现代化的网页架构, 最大的特点就是他只有一个页面, 页面中的内容由 JavaScript 在用户的浏览器上动态生成.
也就是说, 你在网页上的每次点击都是后方的 JS 在帮你发起请求并且更新页面(更新的同时顺带帮你把浏览器地址栏里的 URL 给一起改了). 顺带一提, 我网站上的进度条其实是假的, 那个进度条加载的时候其实浏览器并没有在加载新页面(浏览器的刷新按钮没有变成取消加载就是证据).
现在的主流前端框架基本上都是 SPA 形式的.
SPA 的启动
SPA 因为是运行在用户浏览器上的, 所以首次加载网页的时候需要先加载大量的 JS 以支持上面提到的功能. 举个栗子, 就像是个你的 PC 运行程序, 在运行一个通用程序之前需要先预先启动一个操作系统, 有了操作系统的支持才可以运行.
所以, 一般的 SPA 网页在加载的时候最开始就之后一个空的 HTML 框架, 并且附带一大堆的 JS 脚本. 等这些脚本加载完成后就会自动的向后端发起请求, 根据你现在的 URL 来获取不同的页面元素, 然后拼凑出一个完整的页面.
是不是听着就很高级, 我也这么觉得. 但是这会有什么问题呢, 最大的问题就在第一次加载的时候, 第一次加载除了要加载页面内容之外, 对比 SSR(Server-side rendering, 服务端渲染, 也就是服务端直接返回 HTML 的方式), 还额外多出了很多 JS 加载的成本. 之前在学 React 的时候, 还跟着写出过一个首次加载需要 600KB 的网页, 这意味着什么呢, 如果你的网络带宽只有 10Mbps 的话, 那么你访问这个网页光是 JS 加载就需要花费差不多 0.5 秒!
当然, 上面的问题可以通过分页和懒加载的方式缓解. 比如说我的网站的首屏, 也就是https://gsgfs.moe这个页面, 他的首次加载只需要 120KB 的 JS 文件, 而https://gsgfs.moe/blog这个页面需要加载的 JS 文件大小是 400KB, 但是如果用户访问是https://gsgfs.moe这个页面的话依靠预加载的方式, 可以在用户浏览这个页面的时间里把https://gsgfs.moe/blog的文件提前加载好, 这样就不需要在等待加载上浪费时间了, 毕竟谁也不想盯着网页的白屏看...
除开上面的方法, 还可以使用 SSR 在服务器上预先渲染好部分组件, 直接发送渲染得到的 HTML 给用户, 然后经过一种叫做水合(Hydration)的复杂操作拼凑服务端的渲染和客户端的渲染, 然后在用户浏览器上就不需要这部分组件的 JS 和渲染这部分组件所消耗的算力了.
SPA 的优势
SPA 最大的特色应该就是前后端分离了, 前端部分可以独立开发, 后端只需要维护 API 就可以了.
除此之外, 因为 SPA 始终运行在一个页面上, 可以充分利用缓存功能, 只要之前加载过(或是预加载过)那么再次回到这个页面就是相当流畅的, 因为都是由本地的 JS 驱动, 流畅度基本上可以做到与桌面应用程序相当. 甚至很多桌面程序就是用前端技术写的, 比如说人人喊打的电子(www.electronjs.org). (澄清一下, 人人喊打说的并不是 electron 本身, 而是明明可以在浏览器上解决的事, 非要你安装一个可能之后再也不会用到的应用程序, 疯狂抢占你硬盘空间的某些公司)
说起来, 著名开源流氓 VSCode 就是 electron 应用程序, 你可以在vscode.dev使用网页版的 VSCode, 只不过嘛, 一言难尽... 符合我对巨硬的刻板印象.
PWA
既然很接近桌面应用程序了, 是否可以再进一步呢, 诶, 还真可以, PWA(Progressive Web Apps)可以直接把网页以应用的方式安装在浏览器上.
在最近几次的版本更新里, 我的网站也已经支持了 PWA 技术, 使用 Chromium 内核的浏览器或是 Safari 浏览器的用户可以直接安装我的网站.
安装完成后就类似于下面这样

因为预先将所有的 JS 都安装到本地了, PWA 相比直接网页访问会稍微快一点. 并且, 因为有 Service Worker 的存在, 他也是有缓存功能的, 可以在断网环境下继续浏览缓存的页面. (试了下效果好像不太行, 毕竟不是自己手写的, 还是就这样算了, 不然太麻烦了)