写点什么

ISOMORPHIC 的升级之路

  • 2019-06-16
  • 本文字数:4729 字

    阅读完需:约 16 分钟

ISOMORPHIC 的升级之路

近些年来,史诗级网游 Web Online 中,一个新兴职业 —— Isomorphic JavaScript Application —— 越来越多地得到了玩家的青睐。


Web Online 是一款由地球 Online 玩家基于其游戏平台进行二次开发创作出的网络游戏,特点在于可以自由创建 PC 与 NPC,不过部分地图对于 NPC 的创建管控较严格。主要游戏方式为玩家控制其 PC 与他人的 NPC 聊天以交换情报,也常有自动化的 PC 周期性与 NPC 进行交流。偶尔也有不怀好意的玩家操纵大量 PC 向 NPC 发送大量虚假信息进行攻击。



(该游戏不需要下载,投递简历到《Web 开发工程师》职位即可立即注册)


不过作为高阶职业,Isomorphic JavaScript Application,或者称为 Universal JavaScript Application(以下简称 UJS),并不能在创号时直接选择,需要满足前置的种族及职业要求,包括但不仅限于:


  • JavaScript Application(种族)

  • Frontend Application(职业)


而修炼职业 UJS 后,能够将相关技能更进一步地提升,以及习得部分新的高阶技能。


虽然目前已经有不少玩家都宣称自己是 UJS 职业,不过角色与角色的水平差异依然十分巨大。为此,本攻略中将对 UJS 的相关技能以及等级划分进行归纳,方便广大玩家参考。


需要特别注意的是,并非任何战斗中都需要用到所有技能的最高等级,在无意义的情况下空大只是单纯地浪费 MP(Mana Points),请根据自己的实际情况选择合适的技能。


这里拟定战斗场景为一个简单的 Tab 切换,效果类似于(在线示例):



(示例效果:通过点击修改卡片内容)

职业技能零:浏览器端渲染

该职业由于大部分玩家都已满修,可能不具备研究价值,可根据需要直接跳转到下一技能的攻略内容。


作为 Web 世界的事实专属种族(目前已经一定程度上侵略到其它世界),「浏览器端执行」是 JavaScript 与生俱来的种族技能,为此浏览器端渲染(CSR)也几近标配。


即便如此,鉴于玩家的水平和任务需求,实际使用的技能等级还是具备很大差异:


  • Level 0:无・CSR。应用无法基于静态文件服务器(例如 GitHub Pages)提供。

  • Level 1:伪・CSR。应用获取或生成 HTML 片段,并拼接到页面 HTML 中。

  • Level 2:简・CSR。应用支持全量创建和增量修改页面内容,但需要独立代码实现。

  • Level 3:精・CSR。应用支持全量创建和增量修改页面内容,仅需要一份代码实现。


最早期的 Web 中,所有内容都由服务端页面产生,用户通过超链接访问或者表单提交来进行页面跳转与交互。这时候并不能够进行浏览器端渲染,技能等级为 Level 0。


随着局部刷新需求的出现,部分应用中会通过重置 innerHTML 属性的方式进行内容替换,这样的情况下无需进行整页刷新即可更新内容,使用方式类似于(在线示例):


btn1.addEventListener('click', () => {  outlet.innerHTML = `    <div class="card" style="width: 18rem;">      <div class="card-body">...</div>    </div>  `})
复制代码


为了保持示例代码的简介,整个示例中将不使用任何外部的 JavaScript 依赖,因此只有 VanillaJS 的使用。界面使用 Bootstrap 的默认主题。


这时的技能等级可以达到 Level 1,虽然名义上是局部刷新,但是重新渲染的计算成本较高,并且代码维护及状态管理困难。


为了降低更新视图内容的成本,应用中往往会引入精确视图操作,类似于(在线示例):


btn1.addEventListener('click', () => {  outlet.querySelector('.card-title').textContent = 'Button 1 Active'  outlet.querySelector('.card-text span').textContent = 'foo'})
复制代码


这样可以有效避免渲染引擎的额外开销,进入到 Level 2。


为了进一步简化维护成本,屏蔽视图操作,可以对视图层进行抽象,而后基于数据驱动的手段来触发视图更新,类似于(在线示例):


<div class="card" style="width: 20rem;">  <div class="card-body">    <h5 class="card-title">{{ title }}</h5>    ...    <p class="card-text">Some quick example text to build on the card: {{ keyword }}.</p>    ...  </div></div>
复制代码


为了避免在示例中引入编译过程造成不必要的开销,示例的源码中直接手写了编译后的模版的类似代码。


这样,视图的创建和更新过程得到了统一,并且由于静态内容与动态数据分离,有效降低了应用维护成本,达到了 Level 3。

职业技能一:服务器端渲染

服务端渲染(SSR)大体可以分为三个等级:


  • Level 0:无・SSR。服务端返回空白页面,在浏览器端渲染应用视图。

  • Level 1:伪・SSR。服务端返回 App Shell 级别的应用骨架,在浏览器端渲染实际内容。

  • Level 2:准・SSR。服务端返回用户无关的公共内容,在浏览器端补全用户相关内容。

  • Level 3:真・SSR。服务端返回基于用户的完整真实内容。


前端模版可以分为两种类型:渲染前模版与渲染后模版。(这里只考虑在浏览器中处理的模版,所有在非浏览器中的预处理操作不在此列)


  • 对于渲染前模版,模版自身不会被浏览器渲染,而是被模版引擎直接作为文本处理。因此模版内容任何情况都不会暴露到页面中。典型代表包括 Angular(JIT)、Vue;

  • 对于渲染后模版,模版自身会被浏览器端当作内容渲染,而后模版引擎基于由模版生成的 DOM 树进行后续操作。如果模版引擎出现错误,模版内容可能被暴露给用户。典型代表包括 AngularJS、Vue。


所有手写 Virtual DOM 的场景在机制上等价于渲染前模版,部分视图框架(库)支持多种模式。


对于渲染前模版,由于自身并不被浏览器渲染,因此在 JavaScript 执行前无法提供任何内容,以至于初始等级即为 Level 0。不过即便对于渲染后模版,玩家也基本会为了一致性与安全性,通过样式手动屏蔽模版内容(xxx-cloak),从而主动降级至 Level 0。


示例中假设服务端提供的初始状态为按钮 B 当前活跃,并且已经切换了两次。


Level 0 中的首屏渲染效果如下(在线示例):



(SSR lv.0 (无 SSR) 效果,示例中的导航栏仅用于示例间的跳转,可以视作应用外内容)


这里 SSR 并没有提供任何内容,或者说根本没有 SSR。在没有 CSR(例如 Disable JavaScript)的情况下不具备任何价值。


为了避免完全的白屏,我们可以让 SSR 提供无意义的内容,例如线框图,首屏效果如下(在线示例):



(SSR lv.1 (伪 SSR) 效果,假装这些方块是线框图)


这时首屏并不是空白,而是一个向用户表明「渲染中」状态的过渡视图。这样就提升到了 Level 1,伪 SSR。之所以仍然是「伪」,是因为这里的 SSR 自身不交付任何价值,仅仅作为 CSR 的附属(提供页面渲染过程加速的表象),所以只能算作 CSR+,而非 SSR。


为了让 SSR 能够交付价值,需要在首屏内容中提供实际内容。一个简单的方案是服务端永远作为匿名用户(或者登录中),仅用于产生公共内容,类似于(在线示例):



(SSR lv.2 (准 SSR) 效果)


这时已经非常接近最终视图,唯一的区别是「Hi, anonymous user」。由于服务端并不处理用户信息,仅仅提供公共可用内容,所以需要在 CSR 阶段将「anonymous user」替换为实际用户名,才算完成视图的实际渲染。


Level 2 已经能够在 SSR 中直接交付价值,即便 CSR 失败或者被禁用,用户仍然可以完成对基本内容的浏览。并且由于内容与用户无关,仍然不需要在服务器端进行计算过程(非实时数据敏感的页面),可以在构建时完成全部操作,或者使用基于 API 事件的动态构建策略并缓存。


当然,如果有需要,也能在服务器端直接提供最终视图,效果类似于(在线示例):



(SSR lv.3 (真 SSR) 效果)


为了能够在不使用 CSR 的情况下也能得到最终视图,需要在服务器端进行身份认证(一般基于 Cookie),并且根据用户身份返回专有内容,这时候需要在服务器端进行实时渲染(每个用户的首次访问),可能会占用一定的计算资源。


不过,Level 3 的 SSR 也能提供最为全面的内容交付能力,只要语义化标签使用合理,即便在 Disable JavaScript 的条件下,用户依然能够完成应用的业务流程。

职业技能二:状态过渡

已经单独修炼了 CSR 和 SSR 技能之后,不过要将两者有机结合仍然需要额外的技能。状态过渡大体可以分为三个等级:


  • Level 0:Rebuild。销毁 SSR 产生的全部内容,由 CSR 重新创建内容。

  • Level 1:Rehydrate。在可能的情况下复用 SSR 的视图节点,不再重新创建。

  • Level 2:Resume。集成 SSR 的应用状态,不再重复初始化过程(例如 API 请求)。

  • Level 3:Replay。将 CSR 发生之前的用户交互过程反映到 CSR 结果。


融合 SSR 与 CSR 的最简单方案是:移除所有 SSR 的内容,然后以全新的面貌进行 CSR。这时候如果内容较多,可能会造成页面的卡顿或者闪烁,并且如果存在当前选中文本内容也会被一并清除,效果类似于(在线示例):



(Transition lv.0 (Rebuild) 效果)


Level 0 虽然操作简单,但容易对用户造成明显的不适感。


为了避免页面节点的重绘,可以在 CSR 过程中复用 SSR 结果中已经存在的元素节点,能够一定程度上优化过渡效果(在线示例):



(Transition lv.1 (Rehydrate) 效果)


到了 Level 1 阶段,由于视图节点得到了复用,过渡的体验得到了一定的提升(比如文本选中状态得到了保留)。


重用视图节点的过程一般称为 Hydration,其中会对普通的视图节点进行一定的预处理,以便于运行时类库的使用。不过本示例中其实并没有实际的处理过程。


不过,很容易发现,当前的 CSR 过程虽然复用了节点,仍然没有复用 SSR 中的应用状态,而是重新初始化了应用。为了实现状态复用,可以在 SSR 过程中将应用状态进行序列化,而后由 CSR 过程读取:


<script id="application-state" type="application/json">{  "title": "Button 2 Active",  "count": 2}</script>
复制代码


而后 CSR 中便可复用 SSR 的应用状态,类似于(在线示例):



(Transition lv.2 (Resume) 效果)


到了 Level 2 之后,不仅节点保持不变,而且应用状态也被保持,基本对用户透明。


不过还有一个问题是,在 CSR 开始之前,如果用户尝试对应用进行交互,那么其操作会被无视,类似于:



(Transition lv.2 (Resume) 效果)


为了能够允许在 CSR 发生前进行一定程度的交互,需要进行事件重放。简单来说需要预先引入一个极小的运行时(原则上应当放在内,必要情况下可以内嵌),基于事件代理来记录相关事件,形如:


export function record(eventNames) {  for (const eventName of eventNames) {    document.addEventListener(eventName, (event) => {      list.push({ name: eventName, element: event.target })    })  }}
复制代码


实践中应当基于应用根节点而非文档节点,以免记录到应用外部事件。


之后就可以在 CSR 启动完成后重放相关事件:


export function replay() {  for (const { name: eventName, element } of list) {    element.dispatchEvent(new Event(eventName))  }}
复制代码


接着就能升级到 Level 3,在 CSR 开始前的交互过程也能够被记录(在线示例):



(Transition lv.3 (Replay) 效果)


实际应用中,交互与交互之间可能是相互影响的,为此需要定义 Critical Events,例如:


  • Critical Events:button->click,input->focusout;

  • Non-Critical Events:input->input,*->mouseenter;


Non-Critical Events 允许连续发生,而一旦出现 Critical Events 则立刻阻止用户后续交互(例如弹出遮罩层),直到 CSR 启动并且响应 Critical Events 之后,再重新开放交互,从而避免不预期的应用状态。

写在最后

本攻略主要讲解了 Isomorphic 基本技能的概念以及强度设定,具体实践中可能还有其他不同的技能效果和考量维度,部分经验丰富的玩家甚至能够创造自己的专属技能。


虽然看攻略会一定程度上减少探索的乐趣,不过迫于生活的压力可能更看重通关效率。不论哪个种族哪种职业,打怪升级之路都绝非一帆风顺。不过在了解攻略后,是否对这个职业的角色更感兴趣了呢?

作者简介

余泽江,ThoughtWorks 咨询师,拥有多年 Web 应用开发经验,主要专注于前端框架底层实现与 Web 规范演进。


本文转载自 ThoughtWorks 洞见


原文链接


https://insights.thoughtworks.cn/isomorphic/


2019-06-16 08:005697
用户头像

发布了 98 篇内容, 共 31.5 次阅读, 收获喜欢 249 次。

关注

评论

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

2020非科班生的Android秋招,金九银十求职经历 (快手,android游戏开发实践指南

android 程序员 移动开发

2021年Android开发的前景如何?,安卓面试题及答案

android 程序员 移动开发

2021想进阿里?送你一份 40000 字《阿里进阶指南,android音视频编解码

android 程序员 移动开发

35岁以上员工就要被辞退?你知道互联网行业的“中年,android面试40题

android 程序员 移动开发

2021 年 9 月美团 Android 面试总结,flutter屏幕旋转监听

android 程序员 移动开发

2021年之Android面经分享(已获头条、顺丰,androidapp开发工具

android 程序员 移动开发

3-5年以上的Android原生开发如何深入进阶?高级工程师必须要掌握哪些?(1)

android 程序员 移动开发

2021Android性能优化总结最新、最全面、最完整的资料,大厂内部资料

android 程序员 移动开发

2021了,为什么说音视频技术是技术风口?Android音视频开发这么吃香

android 程序员 移动开发

2021最新Android必备面试题,上海大厂Android面试经历

android 程序员 移动开发

3-5年以上的Android原生开发如何深入进阶?高级工程师必须要掌握哪些?

android 程序员 移动开发

2021年最新Android开发岗面试笔试总结,android开发视频播放器

android 程序员 移动开发

2021程序员熬夜加班,28岁大病一场后被裁看清生活真谛,kotlin协程的实现原理

android 程序员 移动开发

30多个超赞的Android开发者工具,android开发框架开源登录界面

android 程序员 移动开发

35岁以上的Android开发,都去了哪儿?,安卓开发

android 程序员 移动开发

37岁老码农现身说法:那些年,我走过的弯路,手把手教你5G时代Webview的正确使用姿势

android 程序员 移动开发

4年Android开发13K,刷完这份1307页Android-面试全套真题解析,跳槽涨薪15K

android 程序员 移动开发

2020阿里P8单写给Android程序员的建议:这样的offer不能要啊!注意避坑

android 程序员 移动开发

2021字节跳动,金三银四内幕Android中高级面试题合集-令人细思极恐!

android 程序员 移动开发

2579页阿里P8Android学习笔记在互联网上火了,完整版开放下载

android 程序员 移动开发

27道 Handler 经典面试题,你能答出多少?,关于Android程序员最近的状况

android 程序员 移动开发

30岁转行程序员,阿里10年老码农表示:可以转,《Android面试题及解析》分享给大家

android 程序员 移动开发

2021年3月份Android 面经总结!(OPPO和腾讯等大厂,android底层开发百度网盘

android 程序员 移动开发

35岁后程序员自救指南,我拿到了梦寐以求的字节跳动和腾讯双offer

android 程序员 移动开发

35岁教师下岗,自学编程能给我的生活带来多大变化,android指纹识别开发

android 程序员 移动开发

4轮字节面试后杳无音信,自己是在了备胎池了吗?感觉我的Android开发要凉了呀

android 程序员 移动开发

2021最新整理大厂Android面试高频知识点,阿里高级算法专家公开10份资料

android 程序员 移动开发

30w字+的Android技术类校招面试题汇总(附答案,Android框架体系架构的知识

android 程序员 移动开发

30岁程序员:深圳,我终究要来了这座年轻的城市,移动开发者社区

android 程序员 移动开发

3个月8个Offer!2020字节跳动+京东,移动应用开发框架

android 程序员 移动开发

35岁后程序员自救指南(1),写给1-3年安卓程序员的几点建议

android 程序员 移动开发

ISOMORPHIC 的升级之路_大前端_张凯峰_InfoQ精选文章