一天,小风在网上浏览了前端性能优化的相关文章。文章指出:把JavaScript的介绍放在
的末尾小峰想了想,整个人都自闭了……SoAlmost,然后上网查了资料:whyshouldshouldJavaScript的引入要放在的末尾吗?搜索了一下发现网上普遍的说法是:JavaScript的执行会阻塞HTML的渲染,所以JavaScript的引入应该放在的末尾,可以先呈现页面,避免执行JavaScript导致的白屏;出于研究的精神,小峰决定自己验证这个结论,请给小峰点个赞,谢谢(字体本身加粗,转义0.0)大家都知道chrome(文中使用的版本是:86.0.4240.80)是神器,自带性能调优工具,可以记录分析网页的渲染过程:按“F12”或者是“鼠标右键+勾选”打开控制台,选择Performance栏,如如下图所示;我们先创建一个简单的HTML文件,利用Performance来分析页面的渲染过程:你好,小风
从上图我们可以看出网页的渲染过程大致如下:这个阶段解析HTML,生成DOMTree和CSSOMTree;Layout结合DOMTree和CSSOMTree生成LayoutTree(也称为RenderTree),并计算每个元素的大小和位置;UpdateLayoutTree更新LayoutTree;Paint生成PaintLayoutTree记录元素的绘制顺序;Composite合成视图输出到屏幕;在简单了解了网页渲染过程之后,我们来验证一下问题,列举以下两种情况:放在中:你好,小风
在上面的html文件中,我们将放在,是一段包含大量计算的JavaScript。值得注意的是,这里的JavaScript以嵌入的形式存在于HTML中,并不是使用src属性进行外部导入;然后在浏览器中打开html文件,使用Performance分析:script标签放在head标签中。如上图所示,ParseHTML阶段一直处于阻塞状态,直到EvaluteScript阶段结束才重新启动ParseHTML,然后进行Layout和Paint渲染页面流程;在此过程中,页面一直处于白屏状态,直到JavaScript加载完毕才会显示内容;可以看出JavaScript的执行阻塞了HTML的解析和渲染;放在中:您好,小风
接下来,我们将放在的末尾,这里的JavaScript也是一段计算量很大的代码,也是以embedding的形式引入的;然后用Performance来分析网页:script标签放在body标签的末尾如上图,由于JavaScript的执行,ParseHTML阶段也一直被挡住,但是区别就是当EvaluteScript阶段结束后,直接进行Layout、Paint等网页的渲染过程;这个过程页面也一直是空白的,直到JavaScript执行完成;我们可以这样理解:HTML从上到上因此,在执行JavaScript之前正常执行ParseHTML过程:当script标签放在body标签的末尾时,浏览器会先解析HTML,然后遇到脚本标签并开始执行JavaScript。这个过程会阻塞HTML的解析和渲染。因此,页面会一直处于白屏状态,直到JavaScript执行完毕;从以上两种情况可以看出,当JavaScript以内嵌script标签的形式执行时,无论script标签是放在head标签中还是放在body标签的末尾,都会因为JavaScript阻塞HTML解析和渲染,导致白屏,直到加载JavaScript;那么这是否证明网上找到的观点是错误的呢?“不!”因为JavaScript不是通过这种方式引入的,还有另一种更常见的形式:使用script标签的src属性引入外部JavaScript;因此,下一轮验证以引入外部JavaScript的形式开始,脚本标签:放在中:把计算量大的代码移到js文件:index.jsfor(leti=0;i<100000;i++){for(letj=0;j<100000;j++){}}并在html中引入index.js:你好,小风
接下来使用Performance对网页进行分析:如上图,浏览器首先调用Network线程下载HTML文件,然后从上到下解析HTML,直到遇到中的script标签,因为script标签导入了一个外部js文件,浏览器再调用Network线程下载目标js文件,就可以了可以看出这个过程中并没有执行ParseHTML;下载js文件后,浏览器开始执行JavaScript,等待代码执行完毕,开始ParseHTML、Layout、Paint等网页解析和渲染操作;整个过程,网页一直呈现白屏状态,直到JavaScript执行完毕,即导入外部js文件,将script标签放在head标签中时,下载js文件的网络线程会阻塞HTML解析,导致页面一直渲染,直到JavaScript被下载并执行白屏状态;放在中:将script标签移到body末尾:你好,小风
继续使用网页分析性能:如图所示,从上到下解析HTML,执行ParseHTML。当遇到引入外部js的script标签时,Network线程开始下载js文件,同时进行网页的渲染,直到js文件下载执行完毕。JavaScript;整个过程中,网页内容在JavaScript执行完成之前就已经显示出来了,因为在js文件下载之前浏览器已经完成了HTML的解析工作,在js文件下载过程中并没有阻塞网页的渲染过程,所以可以得出结论:“使用script标签导入外部js文件时,js文件的下载不会阻塞网页的渲染,而是阻塞HTML的解析!”为了充分验证上面的结论,我们在script标签后面增加了一个元素:你好,小风
你好小风
观察页面变化,使用Performance分析网页:如上图,网页先显示第一行文字,第二行文字没有出现。此时script标签还在下载外部js文件阶段。意思是Network线程下载js文件的过程阻塞了第二行文本的解析,但是第一行文本可以正常显示,说明这个过程在一段时间后不会阻塞网页,JavaScript被下载并执行,此时也显示了第二行文字;总结结合以上验证,可以得出JavaScript的执行会阻塞HTML的解析和渲染;当使用script标签导入外部js文件时,Network线程会阻塞HTML的解析,但不会阻塞HTML的渲染;所以,网上的大部分观点都是错误的,JavaScript的执行确实会阻塞HTML的解析和渲染,如果以嵌入式的方式引入JavaScript,不管script标签是放在head标签还是放在尾部body标签,页面会因为JavaScript的执行而一直空白;在引入外部js文件的情况下,由于Network线程下载外部js文件只阻塞HTML解析,不阻塞HTML渲染,所以将script标签放在body标签的末尾可以避免由于页面持续空白js文件画面下载时间长!