浏览器与JavaScript

课后整理 2020-12-20

JavaScript主要寄生于Web浏览器中,学习JavaScript语言之前,应该先了解浏览器。目前主流浏览器包括IE、FireFox、Opera、Safari和Chrome。

浏览器的核心包括两部分:渲染引擎和JavaScript解释器(又称JavaScript引擎)。

渲染引擎

渲染引擎的主要作用:将网页代码渲染为用户视觉可以感知的平面文档。不同的浏览器有不同的渲染引擎。简单说明如下:

渲染引擎处理网页,通常分成四个阶段。

第1步,解析代码:HTML代码解析为DOM,CSS代码解析为CSSOM(CSS Object Model)。

第2步,对象合成:将DOM和CSSOM合成一棵渲染树(render tree)。

第3步,布局:计算出渲染树的布局(layout)。

第4步,绘制:将渲染树绘制到屏幕上。

以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的HTML代码还没下载完,但浏览器已经显示出内容了。

重流和重绘

渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具有阻塞效应,并且会耗费很多时间和计算资源。

页面生成以后,脚本操作和样式表操作,都会触发重流(reflow)和重绘(repaint)。用户的互动,也会触发,如设置了鼠标悬停(a:hover)效果、页面滚动、在输入框中输入文本、改变窗口大小等。

重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流。

大多数情况下,浏览器会智能判断,将重流和重绘只限制到相关的子树上面,最小化所耗费的代价,而不会全局重新生成网页。

作为开发者,应该尽量设法降低重绘的次数和成本。例如,尽量不要变动高层的DOM元素,而以底层DOM元素的变动代替。例如,重绘table布局和flex布局,开销都会比较大。

var  foo = document.getElementById('foobar');
foo.style.color  = 'blue';
foo.style.marginTop  = '30px';

上面的代码只会导致一次重绘,因为浏览器会累积DOM变动,然后一次性执行。

下面是一些优化技巧:

【示例】下面是一个window.requestAnimationFrame()对比效果的示例。

// 重绘代价高
function  doubleHeight(element) {
    var currentHeight = element.clientHeight;
    element.style.height  = (currentHeight * 2) + 'px';
}
all_my_elements.forEach(doubleHeight);
// 重绘代价低
function  doubleHeight(element) {
    var  currentHeight = element.clientHeight;
    window.requestAnimationFrame(function  () {
        element.style.height  = (currentHeight * 2) + 'px';
    });
}
all_my_elements.forEach(doubleHeight);

JavaScript引擎

JavaScript引擎的主要作用:读取网页中的JavaScript代码,对其处理后运行。

JavaScript是一种解释型语言,也就是说,它不需要编译,由解释器实时运行。这样的好处是运行和修改都比较方便,刷新页面就可以重新解释;缺点是每次运行都要调用解释器,系统开销较大,运行速度慢于编译型语言。

为了提高运行速度,目前的浏览器都将JavaScript进行一定程度的编译,生成类似字节码(bytecode)的中间代码,以提高运行速度。

早期,浏览器内部对JavaScript的处理过程如下:

第1步,读取代码,进行词法分析(Lexical analysis),将代码分解成词元(token)。

第2步,对词元进行语法分析(parsing),将代码整理成“语法树”(syntax tree)。

第3步,使用“翻译器”(translator),将代码转为字节码(bytecode)。

第4步,使用“字节码解释器”(bytecode interpreter),将字节码转为机器码。

逐行解释将字节码转为机器码,是很低效的。为了提高运行速度,现代浏览器改为采用“即时编译”(Just In Time compiler,缩写JIT),即字节码只在运行时编译,用到哪一行就编译哪一行,并且把编译结果缓存(inline cache)。通常,一个程序被经常用到的,只是其中一小部分代码,有了缓存的编译结果,整个程序的运行速度就会显著提升。不同的浏览器有不同的编译策略。有的浏览器只编译最经常用到的部分,如循环的部分;有的浏览器索性省略了字节码的翻译步骤,直接编译成机器码,如chrome浏览器的V8引擎。

字节码不能直接运行,而是运行在一个虚拟机(Virtual Machine)之上,一般也把虚拟机称为JavaScript引擎。因为JavaScript运行时未必有字节码,所以JavaScript虚拟机并不完全基于字节码,而是部分基于源码,即只要有可能,就通过JIT(just in time)编译器直接把源码编译成机器码运行,省略字节码步骤。这一点与其他采用虚拟机(如Java)的语言不尽相同。这样做的目的,是为了尽可能地优化代码、提高性能。下面是目前最常见的一些JavaScript虚拟机:

浏览器错误报告

浏览器都具有某种JavaScript错误报告机制,但在默认情况下,都会隐藏此类信息,在基于浏览器编写JavaScript脚本时,用户应该启用浏览器的JavaScript报告功能,以便及时收集错误信息。

IE

在IE中可以通过设置让错误对话框一发生错误就显示出来。为此,要打开【工具】菜单中的【Internet选项】对话框,切换到【高级】选项卡,选中“显示每个脚本错误的通知”复选框,如图1所示。单击【确定】按钮保存设置。

图1  设置IE选项

保存了设置之后,就会变成一有错误发生随即自动显示出来。另外,如果启用了脚本调试功能的话(默认是禁用的),那么在发生错误时,不仅会显示错误通知,而且还会看到另一个对话框,询问是否调试错误。要启动脚本调试功能,也可以在【高级】选项卡中取消勾选“禁用脚本调试”选项。

Firefox

在默认情况下,Firefox在JavaScript发生错误时不会通过浏览器界面给出提示。但它会在后台将错误记录到错误控制台中。单击【工具】菜单中的【错误控制台】可以显示错误控制台,如图2所示。错误控制台中实际上还包含与JavaScript、CSS和HTML相关的警告和信息,可以通过筛选找到错误。

图2  Firefox错误控制台

在发生JavaScript错误时,Firefox会将其记录为一个错误,包括错误消息、引发错误的URL和错误所在的行号等信息。单击文件名即可以只读方式打开发生错误的脚本,发生错误的代码行会突出显示。

目前,最流行的Firefox插件Firebug已经成为开发人员必备的JavaScript纠错工具。在有JavaScript错误发生时,Firebug图标会显示错误的数量,单击可以打开Firebug控制台,其中显示有错误消息、错误所在的代码行(不包含上下文)、错误所在的URL以及行号,如图3所示。

图3  Firebug错误控制台

在Firebug中单击导致错误的代码行,将在一个新Firebug视图中打开整个脚本,该代码行在其中突出显示。

除了显示错误之外,Firebug还有更多的用处。实际上,它还是针对Firefox的成熟的调试环境,为调试JavaScript、CSS、DOM和网络连接错误提供了诸多功能。

Safari

Windows和Mac OS平台的Safari在默认情况下都会隐藏全部JavaScript错误。为了访问到这些信息,必须启用【开发】菜单,单击【偏好设置】,然后在【高级】选项卡中选中【在莱单栏中显示“开发”菜单】命令。启用此项设置之后,就会在Safari的菜单栏中看到一个【开发】菜单,如图4所示。

图4  启动Safari开发菜单

【开发】菜单中提供了一些与调试有关的选项,还有一些选项可以影响当前加载的页面。单击“显示错误控制台”选项,将会看到一组JavaScript及其他错误,控制台中显示着错误消息、错误的URL及错误的行号,如图5所示。单击控制台中的错误消息,就可以打开导致错误的源代码。除了被输出到控制台之外,JavaScript错误不会影响Safari窗口的外观。

图5  显示错误控制台

Opera

Opera在默认情况下也会隐藏JavaScript错误,所有错误都会被记录到错误控制台中。要打开错误控制台,需要选择【开发者工具】菜单,单击【Web检查器】命令,打开【Web检查器】,然后选择【Console】选项。与Firefox一样,Opera的错误控制台中也包含了除JavaScript错误之外的很多来源,如HTML、CSS、XML、XSLT等的错误和报告信息。要分类查看不同来源的消息.可以使用左下角的下拉选择框,如图6所示。

图6  错误控制台

错误消息中显示着导致错误的URL和错误所在的线程。有时候,还会有栈跟踪信息。除了错误控制台中显示的信息之外,没有其他途径可以获得更多信息。

Chrome

与Safari和Opera一样,Chrome在默认情况下也会隐藏JavaScript错误。所有错误都将被记录到JavaScript控制台中。要查看错误消息,可以选择【工具】菜单命令,单击【JavaScript 控制台】命令即可,如图7所示。

图7  JavaScript控制台

打开窗口中包含着有关页面的信息和JavaScript控制台。控制台中显示着错误消息、错误的URL和错误的行号。单击JavaScript控制台中的错误,就可以定位到导致错误的源代码行。