JS采用单线程,避免在执行过程中页面内内容被不可预知的重复修改
js的五个常驻线程
浏览器的GUI渲染线程
JS引擎线程
浏览器定时器触发线程
浏览器事件触发线程
浏览器http异步请求线程
当js正在运行某一个脚本时,同一时间点,其他的脚本都处于挂起状态,不能被同时处理,这是js的阻塞特性
当<script>标签出现时,不管是内嵌还是外链,js都会让页面等待这个脚本的加载、解析和执行,所以为了避免用户进入页面出现白屏情况,都是将<script>标签放在body的最后,等待页面内部和样式渲染之后在加载js脚本(JS脚本的下载过程不会相互影响)
当html文件遇到css和图片时,都是进行异步加载,不会对dom的渲染造成影响,但是当html文件中出现js脚本时,会挂起dom的渲染,开始js的加载,并且等待js的解析和执行,才能恢复对dom的渲染
css文件的加载不影响js文件的加载,但是影响js文件的执行,js代码在执行前必须保证相关css文件已经加载且解析完成(避免js中动态改变css的方式发生css冲突)
加载js优化
- script的defer属性,先对script进行解析下载js文件,但是不会执行,使得浏览器不等待js的加载执行结束,即在dom加载完成之前不会去执行,但是此脚本尽量不要对dom进行修改
<body>
<script defer>
console.log('2');
</script>
<script>
console.log('1');
</script>
<script>
window.onload = function() {
console.log('3');
};
</script>
</body>
// 支持defer的浏览器的执行顺序
// 1 2 3
- script的async属性,采用并行下载,下载不会造成阻塞,async加载完成后会自动执行代码,但是defer是等待dom加载完成后执行
- js的预加载prefetch会另外开启线程,提前下载js和css文件,但并不会改变dom结构
- 使用js动态创建script标签,script被添加到页面后立即下载,但是js文件的解析和执行并不会阻塞线程
- XHR脚本注入,创建XMLHttpRequest对象下载js,下载成功后再动态创建script标签,优点在于下载完成后可以控制不立即执行,但是该方法不能跨域使用
css解析时,样式对象从右开始遍历2,即从子元素往父元素查找