我们刚开始学前端的时候,会看到教程在处理外部css和js的时候,会把css放在header,js放在body的最后。为什么要这样处理?今天就结合一些资料来分析一下。首先,将整个页面通过html解析渲染展示给用户。但是无论外链css放在html的哪个位置,都不会影响html的解析,但是会影响html的渲染。如果把css放在最后,可以第一时间显示html的内容,但是会挡住html行中css的渲染。浏览器的这种策略其实是很明智的。想象一下,如果没有这个策略,页面首先会呈现一个内联的css样式,然后在下载CSS后突然改变它的外观。用户体验可谓极差,渲染是有成本的。如果把css放在head中,css的下载和解析可以和html的解析同步进行。如果放在最后,会额外花时间解析CSS,浏览器会先渲染一个没有样式的页面,等待CSS加载完成后,再渲染成有样式的页面,而页面会明显闪烁。为什么要将脚本放在最后?因为当浏览器解析脚本时,会立即下载并执行,打断了HTML的解析过程。如果外部脚本加载时间过长(比如无法完成下载),会导致网页长时间失去响应,浏览器会呈现“假死”状态,即称为“阻塞效应”。具体过程是这样的:浏览器在下载HTML网页的同时开始解析。解析过程中发现script标签的解析被挂起,网页渲染的控制权交给了JavaScript引擎。如果script标签引用了外部脚本,则下载该脚本,否则直接执行该脚本,并将控制权交还给渲染引擎,继续解析HTML。如何处理包含async或defer的网页外链脚本?这两个属性只被header标签中的script标签使用。如果你把它放在正文之后,它就无效了。script的这两个属性主要在js文件不操作DOM时使用。这时候可以将js脚本设置为异步加载,在代码中标注async或者defer即可。async和defer的区别:0,async和defer只对外部脚本有效,对没有连接外部脚本的内置脚本标签,以及动态生成的脚本标签不起作用。1、虽然async和defer都是异步的,但是标有async的脚本文件一旦加载就会立即执行;带有defer标记的脚本文件将在DOMContentLoaded事件之前执行(即页面??DOM加载完成时)。2.如果有多个js脚本文件,不保证async标签按照写的先后顺序执行。无论先下载哪个脚本,都会先执行该脚本。defer标签会按照js脚本的编写顺序执行。3、一般来说,如果脚本之间没有依赖,就使用async属性,如果脚本之间有依赖,就使用defer属性。如果同时使用async和defer属性,则后者无效,浏览器行为由async属性决定。对于async标签,浏览器的解析过程是这样的:当浏览器开始解析HTML网页的解析过程时,会找到带有async属性的script标签。浏览器继续解析HTML网页,并行下载script标签中的外部script脚本。下载完成后,浏览器暂停解析HTML网页,开始执行下载的脚本。具有defer属性的script标签浏览器继续解析HTML网页,同时并行下载script标签中的外部脚本。放在header里,header里会有外链css,那么两者有顺序要求吗?header中script和外链css的位置顺序先结论:如果htmlheader中同时有js脚本和外链css,最好把js脚本放在外链css之前。其实js的执行是依赖css样式的。即js会在所有的css样式都下载完后才会执行。因为如果脚本的内容是获取元素的样式,宽高等CSS控制的属性,浏览器需要自己计算,也就是依赖于CSS。浏览器无法感知脚本的内容是什么。为了避免获取样式出错,必须等到之前的样式全部下载完毕后,再执行JS。但是如果css下载事件很长,js就无法正常运行,导致html无法正常解析。如果css的内容下载的快一些,是没有效果的,相反,JS要等,但是这些等的时间是完全没有必要的。
