网页渲染优化和webWorker多线程前言 当浏览器拿到一份包含js代码的HTML文件时,会先执行同步代码,再执行异步的
前言
当浏览器拿到一份包含js代码的HTML文件时,会先执行同步代码,再执行异步的微任务,当所有微任务执行完毕后,就会去加载HTML渲染页面,渲染完成后再去执行异步宏任务。
根据该事件循环机制,浏览器的主线程是可以被js引擎线程和渲染线程轮流占用的,并且这两个线程是互斥的关系,不能在执行js代码的同时又去渲染页面,因为js语言可以操作DOM结点,万一正在渲染一个DOM结点的同时又对它执行操作,这样会“打起架来”。
所以,js代码的执行会阻塞页面的渲染,那么我们要加快页面的渲染速度,就可以从这个角度出发进行优化,接下来我将给出几种方案——
如何加快一份HTML代码的页面渲染
为了让 js 代码不阻塞页面的渲染,我们可以把 写有 js 代码的<script>
脚本部分写在页面布局代码的下方。因为一份代码的执行是从上往下的,这样 js 脚本放在页面渲染代码的下方就可以避免js代码的执行阻塞页面的渲染
倘若 js 的<script>
脚本就是不能放在页面布局代码的下方,比如要引入某份源代码的 CDN 时,就得在浏览器加载页面之前加载并执行好这份 js 脚本,这样就没办法按照第一种方法那样避免页面渲染阻塞,并且耗时资源请求会使页面渲染更加阻塞
async 和 defer
为了解决这个问题,可以给 <script>
标签添加 async
或者 defer
<script async src="XXX"></script>
<script defer src="XXX"></script>
async
: 让js的加载变成异步,浏览器用一个线程在加载js资源的同时,会用另外一个线程渲染html,当js资源加载完毕后,js代码就要执行,此时HTML的渲染会暂停,等js 执行完毕后再次渲染defer
: 让js的加载变成异步,当js资源加载完毕后,不会立即执行js,而是等到html渲染完毕后,再执行js
Web Worker 进行预加载
js只是默认以单线程的机制执行,但不能说js就是一门单线程的语言,我们可以通过Web Workers开启多线程,这个函数能让web上需要执行的内容以一种脚本的方式运行在另一个线程中,不影响主线程的执行。
通俗点说,就是js单线程在执行的时候,突然碰到一个执行起来比较复杂的工作,比如加载一些图片、或者调用一个AI接口,这时可以利用worker以异步的方式执行这项工作,相当于开了一个子线程,而主线程可以一直执行下去,等到worker把工作做完了直接将结果返回给主线程
当页面上需要渲染很多图片时,除了使用懒加载优化,还可以用 Web Workers进行预加载——开启一个子线程,异步加载图片,不会开销主线程的内存
html结构及js脚本:
<body>
<div id="app">
<h2>图片预加载</h2>
<div id="pic"></div>
</div>
<script>
let picBox = document.getElementById('pic')
let arr = [
"https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF",
"https://t7.baidu.com/it/u=2942499027,2479446682&fm=193&f=GIF",
"https://t7.baidu.com/it/u=3165657288,4248157545&fm=193&f=GIF",
"https://t7.baidu.com/it/u=3240224891,3518615655&fm=193&f=GIF",
"https://t7.baidu.com/it/u=2501476447,3743798074&fm=193&f=GIF"
]
// 为image.js脚本代码开辟一个新的线程
const worker = new Worker('./image.js')
// 发送消息给worker子线程
worker.postMessage(arr)
// 监听来自子线程的消息
worker.onmessage = function(event) {
console.log('主线程:', event);
const img = new Image()
img.src = window.URL.createObjectURL(event.data)
picBox.appendChild(img)
}
</script>
</body>
worker子线程需要执行的工作——获取图片资源:(image.js文件中)
self.onmessage = function (event) {
for (let i = 0; i < event.data.length; i++) {
let xhr = new XMLHttpRequest();
xhr.open('GET', event.data[i], true);
xhr.responseType = 'blob'
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
self.postMessage(xhr.response)
}
}
xhr.send();
}
}
浏览器是多线程的,js代码的执行也可以通过Web Worker变成多线程,在对网页的渲染进行优化时,不妨考虑充分利用这些特性。以上内容希望对您有所帮助!
转载自:https://juejin.cn/post/7415016805015601193