Web Worker在项目中的妙用

10,548 阅读3分钟

最近在项目中遇到了一些性能问题,为了防止图片一张一张加载而影响体验和为了提高效率,需要不断的提前加载数据和大量图片,当时我们在项目中使用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空闲也不会被关闭。