最近在项目中遇到了一些性能问题,为了防止图片一张一张加载而影响体验和为了提高效率,需要不断的提前加载数据和大量图片,当时我们在项目中使用worker来做性能优化,把计算量比较大和图片的预加载放入worker中操作。
什么是 worker
通过使用Web Worker, 我们可以在浏览器后台运行Javascript, 而不占用浏览器自身线程。Web Worker可以提高应用的总体性能,并且提升用户体验。如果你对worker还不熟悉,请参照,在此就不做过多的介绍了,本文主要是介绍worker的应用场景和性能问题。
如何使用worker预加载图片
图片预加载问题分析
- 一般在项目中不会使用worker来预加载图片,而是考虑如何实现懒加载图片,但是基于业务需要所以才使用worker来预加载图片;预加载图片可能你用不着,但是本文应该对你了解worker有很大帮助;
- 加载图片我们有很多方案(不全,如果你还有其他方案希望分享):
- 通过操作DOM里面的Img标签来加载图片。
- 也可以通过js的Image对象来加载。
- 还可以通过ajax来加载。
- 通过不断操作DOM来加载图片是最耗费资源也是最慢的一种方案;通过Image对象来加载比较耗内存而且也会占用主线程的资源;把图片加载放在worker里面来加载肯定是最合适的,但是在子线程里不能操作DOM,所以Image对象也不能使用,只能考虑使用ajax来实现了,很庆幸的是不管用哪种方案加载图片都不存在跨域问题。
具体应用
单独启动一个worker来加载图片,每一次请求回来的数据中都通过postMessage给worker,不多说废话了,直接贴代码:
- Index.js中启用worker
let w = new Worker("js/workers.js");
w.onmessage = function (event) {
/*var img = document.createElement("img");
img.src = window.URL.createObjectURL(event.data);
document.querySelector('#result').appendChild(img)
*/
console.log(event.data);
};
w.onerror = function(e){
e.currentTarget.terminate();
console.log('erro: ' + e.message);
};复制代码
- worker.js中请求图片
let arr = [...好多图片路径];
for (let i = 0, len = arr.length; i < len; i++) {
let req = new XMLHttpRequest();
req.open('GET', arr[i], true);
req.responseType = "blob";
//req.setRequestHeader("client_type", "DESKTOP_WEB");
req.onreadystatechange = () => {
if (req.readyState == 4) {
// postMessage(req.response);
}
}
req.send(null);
}复制代码
总结很重要
- 在worker中使用XMLHttpRequest和在主线程中使用XMLHttpRequest的性能比较,周末特意用node爬了某网站的500多张图片的url来做测试得出以下结论:
- 在主线程中每启动一个XMLHttpRequest请求都会消耗资源,虽然在请求过程中浏览器另外开了一个线程,但是在交互过程中还是需要消耗主线程资源;而使用worker则不会过多占用主线程,只是启动worker过程时比较耗资源。
- 大量的XMLHttpRequest请求时,当网速慢时worker中使用XMLHttpRequest和在主线程上使用XMLHttpRequest感受不到阻塞,当网速很快时大量请求返还时会出现卡顿现象。
在使用worker的过程中发现,如果worker实列引用为0,该worker空闲后立即会被关闭;如果worker实列引用不为0,该worker空闲也不会被关闭。