前言 :之前某次跟狼叔闲聊,聊到前端和后端的对比,还有前端职业的发展。狼叔说,到现在都没有人将前端的体系讲的很清楚,大家都在应用层竞争:前端去搞Serverless,前端去搞AI,前端去搞客户端。我就在想,能不能将我对前端标准化的理解体系化一下,讲清楚。至少可以达成前端对浏览器技术底层技术的一定共识,也就有了这篇文章的大体架构。
前端诞生记
截止2021年6月,全球已经有48亿互联网用户,占全球总人口的61%。前几天抖音宣布覆盖全球10亿互联网用户,但其实有一款100%覆盖48亿互联网用户的APP,它就是浏览器。
1995年第一次浏览器大战,到98年IE统领浏览器,微软的IE达到了巅峰。随后便慢慢开始IE的市场地位被标准化的浏览器实现挑战,其中最有力的就是:FireFox,Opera,Safari三家。标准化浏览器,通过标准规范天然跟开发者亲和,逐步蚕食IE的市场份额。2008年Chrome 的推出,敲响了第二次浏览器大战,Chrome通过崭新先进的技术架构和极致的性能,迅速引领标准化浏览器的实现,Google也主动加入浏览器标准化组织,积极推进浏览器标准化,逐渐Google占据标准化组织中的引导地位。随着2015年IE 推出edge采用了Chroumium,Chrome和Safari等为代表的标准化浏览器实现胜出。浏览器大战告一段落。现在的浏览器厂商都在标准化组织内,浏览器标准化实现相对稳定,开发体验不再分裂。浏览器实现统一,也产生了一系列的连锁反应:跨浏览器抽象兼容的类库JQuery等等逐步退出舞台,浏览器性能的提升也使得模型驱动的MVVM类库流行,从此专业前端职业诞生。
前端-保持对深水区的感知
前后端的开发其实有很多类似的,大致都可以分为3层。需要强调一下,这里并没有高低贵贱之分,只是大家关注的内容不同。
应用层开发,更加偏业务侧逻辑,关注业务逻辑/业务特性/业务领域建模,因此会有开发体验,用户体验,复用性和安全性等等作为衡量指标。
框架类库的开发,关注通用性和跨业务封装,因此衡量指标是:工程/工效,性能,稳定性,基础设施抽象,安全兜底。
而在前后端深水区差异还是比较大的:
- 前端的运行时:浏览器,是完全遵从国际开源组织标准化的应用,而且标准规范对底层操作系统运行环境的封装非常完善,底层操作系统完全透明。
- 后端的运行时的实现大多掌握在闭源商业公司手中,标准规范对跨操作系统的通用能力做了封装,但系统级的开发,还是有大量的操作系统的特性和接口需要关注,因此要求对操作系统层还是要有所感知。
我们今天的文章就是将深水区这层,一层层剥开,带大家看看标准化组织是怎么影响我们前端工作的。那作为一名VUCA时代的前端,我们应该对前端的代码运行时有基本的了解:到底我们的HTML,CSS,JavaScript在浏览器中是如何运行的呢?为什么不同的浏览器执行的结果基本是一致的?他们遵循了什么规范?又是谁在把控,掌握这些规范呢?
经历过浏览器2次大战,现代的浏览器都是基于标准规范实现的(除了还有少量存在的IE8)。因此从标准化的维度来分,浏览器大致可以分为3层:浏览器厂商与实现,标准规范,标准化组织。
浏览器厂商与实现
2021年全球的浏览器市占比:Chrome+Chromium(IE edage, samsung等等)占有72%,Safari占有18.5%,FireFox+Opera占有5.8%,IE内核浏览器0.5%。
从上图可以看出浏览器的市场份额基本已经被国外浏览器厂商瓜分干净了。chrome本身已经具备了65%的市场占有率,再加上chromium衍生浏览器的 7%的市场占有率,一骑绝尘,其后的Safari的市场份额每年相对稳定在18%左右。我们上面既然说现代浏览器厂商(即排除IE8,IE6)实现都是标准化的,为什么还会有差异呢?浏览器厂商他们的差异在哪里呢?
浏览器站队--这个新特性我能用吗?
现代浏览器都要考虑对Web标准覆盖率,因此所有现代浏览器都需要跑通web-platform-tests ,一个专门为浏览器兼容性准备的test case,我们也可以给WPT贡献我们自己的兼容性测试用例。在兼容性以外,浏览器厂商还存在竞争关系,主要的竞争来自两个阵营:
- Chrome为代表的实现开源派代表,基于Blink内核(webkit分支)的Chrome源码是闭源的,但开源了Chromium。可以理解为,Chrome是为了快速迭代开发,尝试各种新架构新特性。Chromium将Chrome较为稳定的部分沉淀,开源反哺到浏览器生态。Chrome倾向谷歌的战略推进与发展。
- Safari为代表的闭源派代表,基于webkit内核的Safari源码是闭源的。得益于苹果的硬件和操作系统闭环生态,Safari的地位很难被撼动。Safari倾向苹果的生态和安全性。
- FireFox和Opera等则是骑墙派(非贬义),缺乏自己主张的新特性。这些厂商大多也是开源的,甚至是Chromium衍生出来的,但是在实现具体新特性时,有时站队Safari,有时站队Chrome。
Chrome和Safari两大阵营,在浏览器标准和规范限定的兼容性边界外做差异化竞争,差异化除了浏览器性能以外,主要是2个方面:默认的行为,例如第三方Cookie,SameSite。未被标准化锁定的新特性:例如新的WebP,HTTP3等等。典型案例就是第三方Cookie,明知道涉及隐私数据泄露,Safari/FireFox/Opera都已经默认禁止了,但Chrome因为涉及到Google搜索广告商的用户追踪和计费策略,加上替代方案的进展也不太顺利,一直推迟禁用第三方Cookie。而浏览器新特性的支持例如WebP等等,Safari的webkit内核设计老旧很明显跟进乏力。而这些差异化内容一旦要引入成为标准/规范时,浏览器厂商们就会在标准规范组织中,相互掣肘和站队,确保自身的利益不被侵犯。
对于我们前端在业务生产环境中使用浏览器新特性,为了确保用户覆盖率,推荐先查一下CanIUse。另外持续关注浏览器厂商的新版本/新特性也很重要,有些默认行为可能会被篡改,有些新特性可以为我们业务创造新的价值。因此我们阿里巴巴前端委员会--标准化组的寒雁同学筹划了《了不起的Chrome》系列文章,通过F2E公众号,为大家持续追踪Chrome最新版本release notes中值得关注的内容。
看完差异,我们接下来看看相同的部分:Chrome和Safari最早都是来自webkit内核,机制上还是有很多共同点的。作为我们前端的代码运行时:浏览器,理解浏览器内核基本原理。浏览器是如何将我们HTML/CSS/JS源码,解析并最终渲染出来的,更有利于我们定位问题和优化代码。
浏览器实现
现代浏览器中,Chrome是比较有代表性的,而且文档也最全面。我们本文中介绍浏览器实现原理也将采用Chrome,以下内容和截图都来自谷歌开发者文档,大家如果有兴趣进一步学习更多细节,也可以阅读原文:Inside look at modern web browser。
多进程模型
图片来源:Inside look at modern web browser
首先现代浏览器的实现都是多进程模型的,例如UI Process负责和我们交互的浏览器窗口,还有Network Process负责处理网络事务,Storage Process负责存储相关的事务等等,多进程模型就意味着进程之间是相互隔离的,进程间通信需要IPC(图中虚线)。这些进程中最值得我们关注的是Renderer Process渲染进程,我们打开每个Tab窗口,就是一个独立的Renderer Process进程。我们常见的CSS, HTML, JavaScript标准规范都在渲染进程里。我们Zoom In看看一个Tab窗口的渲染进程。
单Tab渲染进程中的多线程
图片来源:Inside look at modern web browser
一个Tab窗口就是一个独立的渲染进程,而一个渲染进程则是有多个线程组成的:主线程,Worker线程,Compositor线程,Raster线程。我们前端所熟悉的HTML,DOM树,CSSOM树,JS解析执行,渲染树,页面的计算都在这一个线程中。主线程阻塞,页面就展现的慢。主线程奔溃,这个Tab窗口就奔溃了😵。我们常见的标准规范也都在渲染进程的主线程里。我们再进一步Zoom In看看主线程是如何执行的。
主线程--单线程串行执行
图片来源:Inside look at modern web browser
如上图所示,渲染进程的主线程,是一帧一帧的绘制的。大多数情况下,我们的刷新率都是60fps,也就是说每帧执行间隔为17ms。
我们前端的代码:HTML/CSS/JS,最终都在这一个线程中解析执行,因此我们的代码不阻塞进程就变得尤为重要。当然浏览器将这些细节隐藏的很好,我们大多数情况不需要关心渲染帧的细节,但如果遇到渲染慢或需要极致优化渲染性能的场景,就需要引入requestAnimationFrame,async异步加载,WebWorker,分时分片处理等等手段。推荐大家阅读大漠老师的ATA:消除阻塞页面渲染的资源 和 关键渲染路径(CRP)
现代的前端MVVM框架,核心的逻辑都在JavaScript引擎中执行,而我们如果想再进一步提升JavaScript性能,就需要学习了解JavaScript引擎的知识。例如Chrome的V8引擎。推荐大家阅读知乎文章:JavaScript为什么快(https://zhuanlan.zhihu.com/p/41130608)。
浏览器的实现之所以这么复杂。其源头约束,都来自于浏览器的标准与规范。例如ECMAScript规范就限定了,JavaScript的实现是:弱类型的,动态解释执行的。因此才会有上图V8原理图中的,源码直接进入解析执行,并在执行的过程中,不断优化代码的流程设计,也就是JIT(Just In Time)。
浏览器标准化具体都有哪些标准和规范需要我们关注呢?
标准与规范
浏览器的标准和规范中,我们只关心与我们息息相关的部分:HTML, CSS, JavaScript的规范。
HTML和CSS是由WHATWG和W3C这2个开源组织维护,JavaScript是ECMAScript的实现,ECMAScript(即ECMA-262)是由ECMA的TC39技术组维护。
现在的HTML和DOM规范,主要都由WHATWG来维护。WHATWG还维护了Fetch API,Stream API, MIME type等等规范。而CSS,XHTML规范 ,则由W3C来维护。W3C还维护了SVG,XML, A11y等等规范。大貘老师的知乎文章:我认识的 W3C 规范(https://zhuanlan.zhihu.com/p/425615281)
JavaScript是ECMAScript的最著名的实现,我们前端熟知的ES6,也就是ES2015版本,目前全球的支持率已经高达98%了。因此我们的应用代码中大可去掉兼容ES5语法了,根据Google统计,单单代码去掉ES5支持平均可以提升JS代码执行效率12%。而且Google还做了一个工具检查网站去掉ES5支持后可以提速多少:https://estimator.dev/ 。
对于上述和我们前端开发息息相关的标准和规范,我们应该熟知去哪里查询,对于常见的标准应该了然于胸。虽然我们也可以从MDN查询到简单的描述,但是如果要系统学习和了解更多的技术细节,还是需要查官方文档。HTML和DOM,访问WHATWG的官网查询:https://html.spec.whatwg.org/multipage/ 。CSS通过W3C-->Standards--> Web Design and Applications的HTML&CSS里面的CSS文档查询:https://www.w3.org/Style/CSS/ 。ECMAScript则通过ECMAScript官网查询:https://262.ecma-international.org/ 。熟练标准规范文档的查询,会让你对自己使用的底层接口掌握更多的技术细节,写出更加高效安全的应用。另外推荐大家多熟悉一下ECMAScript规范的大纲。
对于标准和规范,我们熟练掌握和使用能解决日常大多数的问题。但是如果触碰到标准和规范的边界:例如发现一些规范实现的bug想去修复,某些标准相互冲突或者细节不太合理,甚至想引入推进一些新的议题扩展标准。这些都需要加入到标准化组织,才能推进。
标准化组织Jump in
标准化组织并不神秘,而且都是开源组织,但是我们想参与到议题的修改和制定,还是有些门槛的。
W3C
W3C面向自己的会员开放,会员是机构为单位,会员加入W3C不需要获得委员会投票通过,申请即可,每年需要根据机构规模及营收情况支付年费。加入会员后,就可以参与到各类型的Group的中维护具体规范,例如CSS Working Group制定和维护CSS规范议题,A11y WorkGroup制定和维护可访问性的规范议题。Web技术跟国内互联网大厂紧密,因此国内大多数互联网大厂都已经加入了W3C,我们只需要找到公司内对应的负责人,即可申请加入。值得一提的是,阿里巴巴的标准化组朱红儒(茱滴)已经第四次当选W3C董事会成员。
ECMA
ECMA也是面向自己的会员开放,会员是机构为单位,会员需要申请,并获得ECMA的委员会投票同意加入,每年需支付年费。同样加入会员后,就可以参与到各个技术委员会TCs,影响相应的议题。例如ECMAScript就是由TC39技术委员会维护的。除了ECMAScript,ECMA的TCs维护着Dart,C++,C#等规范。相对于W3C,国内加入ECMA的大厂较少一些,360第一个加入ECMA之后,阿里巴巴紧随其后,今年字节跳动也加入了ECMA。关于最新的ECMAScript提案的进展,我们阿里巴巴前端委员会--标准化组 ,也为大家准备了《TC39月会》跟踪,为大家持续更新TC39每期月会的进展。国内的工程师,如果有改变ECMAScript标准的诉求,也可以加入JSCIG。
WHATWG
最难参与的标准化组织是WHATWG,WHATWG相对封闭,由核心浏览器厂商组成的steward进行管理,steward并不对外招收会员,由内部成员自己维护规范,但是通过Github issue的方式吸收社区的反馈意见,具体是否采纳社区反馈,由2-3名核心editor决定。
个人加入前置条件
个人加入标准化组织有三个前置条件:
1. 英文好。W3C虽然有中文社区,但英文阅读和书写能力还是比较重要的。ECMA对非英语言更不友好,基本需要英语口语能力很强。
2. 熟读标准和规范文档。在标准化组织中,这些文档是大家的基础背景知识,尤其是了解英文专业词汇。
3. 有参与或者推进的具体议题。这点其实尤为重要,有切实具体的推进议题,才有动力坚持克服议题推进的障碍,并在技术小组中持续活跃。
议题推进过程
目前标准化组织的技术委员会或者工作组中,都由行业专家和业界大牛们在把关。包括浏览器厂商自己想推进一些议题,也没有那么容易,技术组中大家彼此之间更多的是博弈站队。因为任何一个简单议题,都可能会对整个前端生态影响深远,而且要防止整个技术组成为一言堂。所以我们有时反而很庆幸,还有Safari这样一个Chrome无法吞并的重要闭源浏览器,可以跟Chrome抗衡。推进议题,更多的是游说和文档的工作,将各方的意见能达成平衡统一后,就可以推进到下一个阶段。当然发展到现在,各个技术组中也已经存在大量无法达成共识的僵尸议题,因为各种原因无法继续推进。推进的后期阶段后,则是写文档和测试代码,最终浏览器厂商,会在未来的迭代中排期实现。
在标准化组织中成功推进议题,还是比较有成就感的。
阿里前端委员就成功的将Error Cause议题推进到了Stage4,并被录入ECMAScript2022成为正式标准。国内第一个自主提案推进到浏览器标准,目前各大厂商的浏览器都已经实现支持。大家可以直接在浏览器的console中体验了:
async function doJob() { const rawResource = await fetch('//domain/resource-a') .catch(err => { throw new Error('Download raw resource failed', { cause: err }); }); const jobResult = doComputationalHeavyJob(rawResource); await fetch('//domain/upload', { method: 'POST', body: jobResult }) .catch(err => { throw new Error('Upload job result failed', { cause: err }); }); } try { await doJob(); } catch (e) { console.log(e); console.log('Caused by', e.cause); }
总结回顾
浏览器标准化跟我们前端行业息息相关,现代浏览器是一个高度标准化的产品。各个浏览器厂商虽有竞争,但在标准化层面统一。所有浏览器的实现都受到标准规范的约束,这些标准和规范,提供给了我们前端一个稳定的生态系统基座。标准规范的内容,则是由开源组织中一堆的行业专家和业界大牛们坚定的维护,浏览器厂商要推进新特性,也需要在标准化组织中相互博弈妥协。
阿里巴巴前端标准化小组梳理了以下内容:
- 应用层我们正准备开源《阿里巴巴前端规约》并配套了F2ELint工具,将计划和社区共同维护,且持续更新前端代码的最佳实践。
- 厂商/浏览器实现层,将持续跟踪Chrome新版本release notes中,值得关注的内容:《了不起的Chrome系列》。
- 标准化组织层,将持续跟踪TC39每期月会的最新提案进展《TC39月会》。
- 另外我们浏览器标准化归类在阿里前端知识图谱(https://f2e.tech/)的初阶:前端基础,行业标准。
欢迎关注我们的内容专栏:ECMAScript 双月报告专题
放在最后
标准化组织也是开源组织,不过是由厂商和业界专家们维护的开源标准规范。毫不夸张的说,前端就是在开源生态上生长起来的。作为前端应该意识到开源对我们的价值,更多参与开源共建项目。即使没有机会参与浏览器标准化组织,我们也可以参与到其他前端开源项目,共同维护前端开源生态的发展的。另外希望大家可以坚持贡献开源社区,共同维护前端的基座,推进行业发展。