一、一些有关Web开发的常识

window对象的子对象分很多种:

子对象 说明
document 文档对象用于操作页面元素
location 地址对象用于操作URL地址
navigator 浏览器对象用于获取浏览器版本信息
history 历史对象用于操作浏览器历史
screen 屏幕对象用于操作屏幕的高度和宽度
onclick 当用户点击某个对象时调用的事件句柄。 2
oncontextmenu 在用户点击鼠标右键打开上下文菜单时触发
ondblclick 当用户双击某个对象时调用的事件句柄。 2
onmousedown 鼠标按钮被按下。 2
onmouseenter 当鼠标指针移动到元素上时触发。 2
onmouseleave 当鼠标指针移出元素时触发 2
onmousemove 鼠标被移动。 2
onmouseover 鼠标移到某元素之上。 2
onmouseout 鼠标从某元素移开。 2
onmouseup 鼠标按键被松开。 2

玩转代码|Script 标签中的async与defer属性详细分析_ async-CSDN博客

readyState属性值

返回值 说明
0 未初始化。表示对象已经建立,但是尚未初始化,尚未调用 open() 方法
1 初始化。表示对象已经建立,尚未调用 send() 方法
2 发送数据。表示 send() 方法已经调用,但是当前的状态及 HTTP 头未知
3 数据传送中。已经接收部分数据,因为响应及 HTTP 头不安全,这时通过 responseBody 和 responseText 获取部分数据会出现错误
4 完成。数据接收完毕,此时可以通过 responseBody 和 responseText 获取完整的响应数据

JS XMLHttpRequest入门教程(非常详细) (biancheng.net)
JS Ajax请求(简明教程) (biancheng.net)

二、好文分享

为什么用 electron 开发的桌面应用那么多?

在瞬息万变的互联网行业中,年过二十四的即时通讯IM应用 QQ 堪称超长寿的产品,见证了中国互联网崛起的完整历程。

然而,如今这个元老级产品经历了一次从内到外彻底的重构。在这次重构中,QQ 选择了 Electron 作为 UI 跨平台开发框架。

尽管 Electron 被 Slack、Visual Studio Code 和 Discord 等大型产品广泛使用,但也引发了一些网友的担忧,例如内存占用、安装包体积和启动速度等方面的问题。本文内容整理自 QQ 技术团队的采访,我们一起来看看QQ团队选择Electron作为桌面版跨端框架背后的决策与思考。

1、老QQ桌面版的技术债

1.1多端代码不统一

QQ 的第一个版本发布于 1998 年,在 Windows 技术栈的基础上用纯原生的方式开发,在当时互联网带宽非常小的情况下,QQ 将安装包控制在了只有 200K 左右。

2007 年后智能手机开始露出苗头,腾讯行动得比较早,部分前端技术开发开始转型到了移动端,在桌面端, QQ 随着业务和组织的发展,针对三大操作系统陆续组建了三支不同的研发团队,各自负责自己的一套代码。

▲ 初版QQ的注册向导页

▲ 初版QQ的主要功能为即时聊天

三端不同代码,老产品历史包袱,加上移动时代研发人员的转型,导致桌面 QQ 维护成本很高。

QQ 技术团队介绍,拿之前的桌面 QQ 为例,Windows QQ 以前的 UI 框架用的是腾讯自研的 GF 框架,10 多年了,GF 这个框架文档还不全,新加入这个项目的团队人员,要基于这个基础框架去做一些事情,是效率很低的一件事情,慢慢的就没有人愿意去用这个框架了。简而言之,就是技术债

_PS:_如果你对QQ的发展史感兴趣可以看看下面这些文章:

  1. 闲话即时通讯:腾讯的成长史本质就是一部QQ成长史
  2. 技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码
  3. 技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史
  4. QQ的成功,远没有你想象的那么顺利和轻松
  5. 还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

1.2多端功能不一致

旧版的桌面端 QQ,Windows 的功能最丰富,Mac OS 次之, Linux 功能非常简洁。

比如“屏幕共享”这个功能,移动端有,Windows 端有,但是 Mac OS 端是没有的。那用户就会遇到一个问题,像 Mac OS 端无法与其它端 QQ 用户一起来使用这个功能。

“多端不统一不利于用户对于 QQ 的统一认知。我们这次的架构升级就是想尽量通过一套核心代码去拉平所有平台的体验,让它具有更好的可维护性可扩展性,让桌面 QQ 能够更好地迭代产品交互和功能,升级用户体验,再次焕发生长的生命力。”

1.3QQ NT 项目的诞生

于是 QQ NT 项目的诞生了!

QQ NT 项目是在 2022 年 3 月份正式启动, Mac OS QQ 在 6 月份开始发布内测, 9 月份正式上架了 App Store,迭代了几个版本之后,QQ 团队就同步开发 Linux。

在 2022 年,QQ 发布了新的 macOS 和 Linux 版本,包括 QQ 后台其实也做了很大的改变和重构,核心系统做了全新重写,云原生成熟度也得到了很大的提升。

从 2023 年开始,QQ 团队聚焦做 Windows 端的开发,在 3 月底就开始内测,7 月初上架官网。

同时移动端 QQ NT 也在 7 月初完成了核心系统的重写和全量升级。

在目前全新的框架设计下,无论是核心系统、功能迭代还是设计语言上,都可以尽可能地“原子化”,来让 QQ 后续更好地迭代功能。

2、新QQ桌面版重构的技术挑战

2.1业务功能上的挑战

QQ 的重构其实是两方面的重构:

  • **1)**一个是面向复杂业务的梳理重构;
  • **2)**一个是面向工程技术债的全新技术重构。

重构之路也是两者相互伴随的过程。

首先:在整个 QQ 重构过程中最大的挑战来自于 QQ 功能的复杂化,QQ 有很多十分复杂的历史功能,这些功能模块也曾经由非常多不同的人经手负责过。其中哪些功能是不合理的或没有价值的,如何去做取舍往往是最难的。“虽然技术上我们做了很多事情,但技术上的实现或许并没有那么难,我们处理起来更有经验和从容。相比于技术的复杂度,业务上的往往需要考虑的更多,这本身就是很大的挑战。”

因为 QQ 已经是近 25 年的产品了,有很多细小复杂的功能。虽然这些功能看看起来很小,但用户量其实又很大,稍微改动可能就会有很多的用户反馈,QQ 团队都得非常的关注。仅从产品功能角度上看,有些功能本身就已经是很重的负债,而 QQ 团队内部有一个叫做“QQ 节能计划”的项目,会有比较严谨的项目流程去评估是否需要下架。

2.2技术重构上的挑战

技术上重构也有不少挑战,这次重构是一次跨平台的重构,而在多个平台里面比较有挑战则是 Linux 平台。

作为程序员,很多人免不了要跟 Linux 打交道。但是这么多年来,对于使用 Linux 系统的用户来讲,有一个特别让人烦恼的问题,那就是没有一个好用的 IM 聊天工具。被寄予厚望的 QQ,此前在 Linux 版本上功能也没有 Windows 和 Mac OS 版本全面,迭代速度也明显慢过其他两个版本。业界甚至猜测 Linux 第一个版本是由腾讯实习生所写,毕竟这个说法进一步加重了其初版的“简陋”特性,也为其“停更”的原因提供了更合理的解释。

QQ 技术团队表示,较之另两个版本,Linux 版本的研发最为复杂:

  • **1)**一方面操作系统本身很多碎片化,市面上有非常多的发行版,也不缺乏一些千奇百怪的版本;
  • **2)**另一方面因为机器运行环境或编译器的缺失,使得解决适配问题的难度很大。

许多发行版相关的机器和开发环境实际上他们并没有,有时还需要外部公司帮助进行一些测试工作。由于没有相应的开发环境,一旦出现闪退等问题,解决难度自然会变得更大。此外,有时候需要与国产操作系统厂商进行特殊的合作,甚至需要对方寄送特定的编译好的代码库,但前后往往会花费一个月的时间才能收到。

而在本次重构之后,“Linux 功能跟 Windows 一样多了”。

2.3选型Electron的质疑

技术上的另一大挑战便是外界对于 QQ 桌面端使用 Electron 的质疑,尤其是内存方面。

外界有些用户在没有使用和分析的情况下对此发表一些夸大和否定的言论,也确实给 QQ 技术团队带来不小压力,但他们却始终坚定选型方向,也相信其中的问题可以被攻克和解决。

3、为何选择Electron而非纯Native技术栈

3.1为什么Windows端不用原生实现?

确实当时有很多人在问,为什么 Windows 不用原生去实现?为什么不用 Qt?

首先:不太想和以前一样,Windows、Mac OS、Linux 三端各由一个团队分开负责。在国内这种人才环境里面,相关的纯原生的开发人员其实非常难招了,桌面端的人才稀缺,同时也投入比较大。

而对于 Qt 技术栈,他们首先考虑的其实还是人才的问题,国内熟练 Qt 技术栈的人非常少。如果对这个框架不了解,使用它反而是一个负向作用

至于微软的 Webview2,从本质上讲,Webview2 和 Electron 并没有太大的区别,只是相对在其中打包了一些微软自身的优化措施,其他方面也不是很完善,而且还无法跨平台。虽然内存方面相较于 Electron 做了更多的优化。但据了解,比如微软 Teams 也没有完全切到 Webview2。并且由于它没有开源,因此也没有办法基于 Webview2 做定制优化

包括 Flutter,QQ 团队表示他们当时也有过调研。他们放弃的一个原因是 Flutter 在桌面端的完善程度并不高,也担心标准化的问题。虽然当前 Flutter 非常流行,但谁也说不好这是不是“2015 年的 React Native”。大家担心随着时间推移,这套技术可能会失去维护支持,因为本身 Google 使用 Flutter 的占比也比较小。

“虽然它很热,但我们历史上踩过了很多很多非标准化的坑,一旦某个技术栈热度一过、维护力度不够,它就会成为全新的负债,做选型时必然也是避免再有类似经历。”

3.2选择Electron的几个考量

至于为什么最后选择 Electron,QQ 技术团队表示主要是基于以下几个考量。

_1)_首先最看重的是框架成熟度和技术栈的标准化:

Electron 基于 Web 技术栈,有足够低的上手和使用成本,不需要为了使用框架本身,还需要投入额外巨大人力成本去做基建和周边工具链的建设,以前在 RN、Flutter 的实践上都有类似的情况。而使用 Electron,现有的 Web 前端的大部分基建都可以直接复用,而且使用 Web 开发 UI 的效率,在主流技术栈里算是很高的了。至于迭代效率我觉得从新版桌面 QQ 功能的迭代速度就可以证明,这放在以前是完全办不到的。

另外由于 Web 技术栈是标准化的,假如 Electron 修改开源协议或者要闭源了,他们也能很方便的去写出一套类似的框架。只不过现在已经有开源的了,没必要再去重复建设一个。而且随着 Web 标准长久发展,Web 技术栈也不会有大的问题,而且还会越来越好。

_2)_其次是技术经验及人才储备:

技术选型是否适合当前团队也是一个很重要的考虑点,团队是否有相关的技术积累,是否有人才储备来持续投入这个技术栈。

Qt 的确在性能上是一个很好的选择,但目前团队对 Qt 没有太多积累,基建基本没有,而且相关人才其实比较匮乏,招聘就更难了。

而当前 QQ 技术团队 Web 前端团队还是有比较多的积累,在 QQ 频道项目中,也完整验证了 Electron 的技术可行性。

_3)_最后就是 Electron 具备的桌面端跨平台的优势:

但 QQ NT 架构并不是仅指 Electron,Electron 主要是作为 UI 跨平台的框架,只是占比很小的一部分,并且 QQ 桌面端不是全部用 Electron 实现,QQ NT 最核心的部分还是 QQ 底层通用抽象的模块,称之为 NT 内核,包括核心登录、消息系统、关系链、富媒体、长连接、数据库等等模块,完全用 C++ 实现,全平台通用。因此底层是完全跨平台的架构,而 Electron 只是上层桌面端 UI 跨平台较薄的一层。

“其实我们当时选型的时候,也的确看得到大家对 Electron 的评价褒贬不一,但我们还是有信心去解决这个问题,前期也做了一些技术的 Demo 和预研。实际上 Electron 并没有糟糕到这个地步。我们觉得可能是国内很多没有用过 Electron 的开发者,对这个框架有些忌惮。其实你到 Electron 的网站去看,还是有非常多国内外的亿级 DAU 产品都使用 Electron 框架。目前这几年主流的桌面端应用基本都选择了 Electron,如 Visual Studio Code、Discord、Slack、Skype、Whatsapp、Figma 等等,新的应用基本上也是首选 Electron,版本的迭代速度和社区氛围都很在线。”

“我们觉得不需要单纯因为口碑问题,就对这个选型没有了期待。还是要从实际出发,哪种技术栈适合你的产品,看看到底能不能有技术实力去把这个事情搞定。”

4、如何有效控制Electron的内存占用?

外界之所以会觉得 Electron 内存占用高,是因为其本身是一个多进程的架构,主进程基于 Node.js, 而每个窗口都对应一个渲染进程以及 V8 实例。可以说从技术框架层面上,上手写代码很容易,但不容易去管控它的内存。

QQ 技术团队认为:Electron 的开发者更多的是前端的开发者,可能在思维上没有去考虑怎么在这样一套技术框架里,去对内存数据进行管理和管控。开发者需要从前端开发者的思维,转变为客户端开发者的思维。

综合来看:对内存的看法其实不完全是 Electron 的技术框架所导致的,更多的是门槛上、开发思维上,导致内存没有得到很好的关注和优化。其实最简单的 Electron 应用大概也就只有几十兆的内存占用。因为前端原本更多还是停留在开发即用即走的 Web 站点,很少实现一个超大客户端,缺乏控制内存的经验,所以面对 QQ 这么大一个产品的时候,你就必须非常在意内存的使用和管控。

至于优化内存的突破口,可以说是从各个层面:从消息的链路中的每条消息的收发上,数据是怎么管理,包括像窗口及会话的管理,都得精打细算,也会做一些数据本地化和一些机制的按需加载,包括渲染上他们也提出一个根本的原则:“要做到所见才占用”,既我们看到的内容才占用这一部分内存,没看到和用不到的任何场景的内存就不应该再占用,通过各种方式来去让内存达到一个设定的目标。

他们也使用了不同维度的内存分析工具,从 V8 引擎到进程,再到整个应用程序,打通整个链路进行多角度的细节分析,以此来定位内存使用的瓶颈。之后采取一系列的针对性优化策略,包括缓存策略、按需加载、优雅降级等,同时使用线上监控、自动化测试手段,包括借助开发框架、工具建设、代码审查等,来阻止性能退化。(更多细节可以参看技术文章:《IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存占用优化》)

经过一系列组合优化之后:QQ 的内存在长时间挂机的条件下,平均稳定在 220M 左右。“现在优化还是不错的,比老版本要好很多。我们认为这个难题还是可以被很好的攻克,内存并不是大家认为的这么不可控,但是也需要团队去花费相当精力去探索和实践,才能去把内存控制到一个比较理想的状态。”

5、未来展望

目前 QQ 的前端团队作为一个公线团队,不仅负责桌面 QQ 的研发,还有 QQ 基础运营、QQ 空间以及基于 QQ 生态的创新项目研发,有比较多的线上项目的开发与维护和内部研效工具的建设。涉及的技术栈,包括 H5、Electron、Cocos、小程序、WebGL、WebAssembly、WebRTC 等。他们也表示会继续夯实这些技术,同时也不断地打破立下的性能目标,希望让桌面 QQ 覆盖更多平台。

他们也正在积极拥抱 AI:让 AI 在质量和效率上辅助日常开发。比如:前端设计稿还原,之前更多是一个耗时的体力活,D2C 是 QQ 前端一直探索的方向,之前使用纯规则转换生成代码,在视觉还原上效果还不错,但是代码可读性和可维护性不能很好的满足预期,所以除了一些日抛型的运营活动有些使用之外,比较难扩大成果。现在 D2C 结合大模型,生成的代码质量高了很多,也能很方便的将代码与 UI 组件库做映射,达到可以在核心业务中高效使用,达到通过 AI 提升研发效率的目的。针对一些无设计稿的管理平台开发,使用 P2C 提效,目前也有了一些不错的案例。

另外:QQ 技术团队也在积极探索 AI 更广阔的应用场景,比如代码评审,基本的 Lint 检检是难以实现的,但将已经掌握的内存泄漏模式通过规则的形式给到 AI,可以很方便地给开发同学一些不错的建议,为性能看家护院提供多一道保障。

6、写在最后

QQ NT 项目于 2022 年 3 月份启动,Mac OS QQ 花了该团队 3 个月的开发时间,9 月份上架 App Store,迭代了几个版本后同步开始开发 Linux QQ,并于这一年的最后一天上架各 Linux 应用市场,作为给 Linux 用户的一份特殊的新年礼物。2023 年 QQ 团队开始去聚焦做 Windows QQ NT 的开发,7 月正式上架应用市场和官网。同时移动端的 QQ 从 2022 年的 Q4 开始开发,也已经完成了全量升级和发布。

另外:桌面 QQ 也是在 NT 版本中第一次支持 64 位,这需要将音视频、安全、字节码、图形库等 C++ 模块,包括 Electron 框架都重新进行编译,花费了比较大的工作量。但在 64 位系统上,QQ 从此便不再需要以 32 位应用的方式通过额外的兼容和转换来运行。毕竟额外操作会增加开销,导致性能下降。

至此:QQ 实现了多个系统平台之间架构的统一。而团队的未来规划还是不断地打破性能目标,并覆盖更多平台,同时探索更多提升研发效率的办法,加快研发速度。

腾讯 QQ 用跨平台 Electron 取代之前原生应用程序的开发模式,这一举动引发的反响确实巨大。但我们也能看出,不同于小型产品团队,在大公司里具有一定规模的产品组织架构之下,快速满足用户需求,并逐渐需要为第三、第四乃至第五种运行平台提供支持时,保持一致性和协调性并不是想象中的那么容易。而缓慢而低效,最终会令你输掉比赛。

不管使用什么跨平台开发框架,都要去选择最合适自己团队的,也因此在 Web 标准技术栈上有丰富积累的 QQ 团队才会选择 Electron。并且我们认为没有人真正讨厌 Electron,只是我们对 QQ,对国内 App 寄予了非常高的期盼。