Rebornix

作为使用 Web 技术的代码编辑器从业者,关注 Web 平台的各种新提案是工作的一部分。随着 Monaco Editor 被很多服务使用,我也开始收到各个新提案的发起者的邀请,对他们的提案提供反馈。其中一些提案跟编辑器开发效率和性能优化息息相关,但还处于非常早期的阶段,十分有潜力,所以我觉得值得分享出来,这样大家有机会可以参与到这些提案的设计讨论中。

首先,这篇文章的适用人群

好了,废话少说。本文要介绍的提案包含以下几个:


Keyboard Map

提案:Keyboard Map

首先要介绍的提案 Keyboard Map,其实在我前面的几篇博客详细介绍过了 。如果你的产品的用户,使用非 US 标准键盘的话,请务必详细阅读下面这个系列的文章。

简言之,在不同的标准的键盘上,按下同一个物理键时输入到系统中的字符可能是不同的。比如在 US 标准键盘上,Shift 旁边的键是 Z,而在德语键盘上则是 Y。

这个提案,就是为大家提供一个物理键和字符之间的映射关系,至于它能解决什么问题嘛,还请阅读上面的系列文章,抱歉,五百字可能都解释不完。

Edit Context

提案:EditContext API - WICG

第二个要介绍的提案,来自微软的 Edge 团队。当我看到这个提案的时候,我是非常激动的,因为它就是为 Web 平台文档和代码编辑器设计的。

Web 平台要做一个文档或者代码编辑器,光靠 Textarea 和 Input 是肯定不行的,要实现文字多样式、快捷键支持、文档虚拟化渲染,大家一般会使用下面两种方案

第一个方案,通过创建一个隐形的 textaea,监听发生在这个上面的所有事件,比如 InputkeyDown等等,然后再将输入的内容按照格式渲染在页面中。也就是说,textarea 监听事件,而用户看到的内容都是虚拟渲染出来的。

这种方案的工作量其实是非常大的,因为连 cursor 和 selection 都是自己渲染的。而且这也意味着,在触摸屏上,基本上没法通过手指选择文字。

而 ContentEditable 这个 API 的推出就是为了更方便的实现 WYSIWYG 编辑器的 API,但是 ContentEditable 早年的 bug 实在是太多了,大家在 textarea 这个方案上走的非常远了。现在 ContentEditable 成熟度好多了,但它有几个局限

EditContext 这个提案,解决方案是将用户输入这系列 API 独立出来,应用只需通过 EditContext 这个新的接口来接收用户的输入。换成大白话来说

这个提案看起来还是很有潜力的,如果最终的实现能够提升触屏上的使用体验,以及提升 Accessibility 的话,那是很值得一试的。

Highlight API

提案:MSEdgeExplainers/highlight

Edge 团队另外一个有趣的提案就是 Highlight API。这个更好理解了,你可以异步地通知浏览器调整某段 DOM 节点的样式。

现在大家的做法都是在生成 HTML 的时候,就直接带上了样式信息(inline 或者通过 CSS)。Highlight API 将这个过程异步化,既简化了结构,又让渲染变的更加可控。理论上,Highlight API 的性能能更好些,也更干净。


如果说上面的提案跟编辑器强相关,下面的这两个提案就相对更通用了,对于大部分 Web 应用的性能优化都有潜在价值。

通常来说,页面中 DOM 结构越复杂、节点越多,给浏览器渲染带来的挑战就越大。解决这个问题的一个主要方法,就是把用户暂时看不到的内容暂时不塞入 DOM 中。Problem Solved。

这么做优化了性能,但是带来的体验上的问题却不小:

  1. 当用户需要滚动页面时,将要看到的内容还未加载到页面中。我们需要在此处截断,提前把用户将要看到的内容塞入页面中。
  2. 滚动条比例不正确。我们需要自行渲染滚动条,以展示当前页面在全部内容中所占的比重。
  3. 浏览器默认的搜索框无法搜索全部内容。我们需要实现额外的搜索组件。

前两个难题,一般来说,只要你是使用主流的框架来开发项目的,基本坑都已经被填好了,按照 “框架名 virtual list ” 进行搜索就能找到答案。解决方案一般都是

完成上面的方案,对算法功底和浏览器渲染机制都是有一定的要求,而且每个框架,都可能需要一个自己的 virtual list。

而下面这个提案,就是要救大家于水火。

Virtual Scroller

提案:virtual scroller

顾名思义,就是提供一个实现 virtual list 的内置方案,你负责塞数据,我负责渲染,而且尽可能保证只渲染用户需要看到的。语法也很直观:

<virtual-scroller id='scroller'>
  <div>Item 1</div>
  <div>Item 2</div>
  ...
  <div>Item 1000</div>
</virtual-scroller>

一个新语法,解决三大问题,不需要用户根据滚动加载数据,滚动条比例正确,浏览器也能正确搜索。不要问有什么潜在问题,问就是银弹。

当然我们知道,哪怕 virtual scroller 真的可以做到按需渲染,但我们也不能真的把内容全部都塞到 DOM 中。比如你打开一个文件,一百万行代码,如果全塞进去,再牛的引擎也不行。因此 virtual scroller 也是允许你自行做 paging 的,它会根据滚动的情况释放 rangechange 事件,让你有机会往里面塞入更多的内容。

到这里,哪怕你对实现一个虚拟化的 list 组件没什么概念,你肯定也意识到了,无论是土方法还是 virtual scroller ,万变不离其宗,都是减少渲染开销嘛。既然目标这么明确,那么干脆就对阵下药好了,Chrome 团队又提出了一个相对更底层的 API:Display Locking,让你直接控制渲染。

Display Locking

提案:Display Locking

一句话,将部分 DOM 节点锁定,让它跳过 rendering 这个环节,等到需要的时候再进行 render。

有了这个 API,上面的 Virtual Scoller 是不是实现起来也很简单?我们把所有 list item 都加载到 DOM 中,但是 lock 住用户看不到的部分。然后在 idle 或者用户滚动的时候,增量地渲染。

Virtual Scoller 抽象程度更高,解决的是 list view 这一类型的问题,而 Display Locking 这样底层的 API,你几乎可以用在任何地方。


小结

以上这五个提案,只是抛砖引玉,大家可以在 WICG 这个 github organization 里查看各种新提案,每个都有自己要解决问题。如果它们刚好跟你们的业务相关,不妨参与到提案的讨论中。

<推广> mCast: macOS 播客客户端,搜索、订阅、播放一气呵成。



blog comments powered by Disqus