likes
comments
collection
share

前端性能优化-图片预加载前言 今天我们聊聊前端性能优化系列之图片预加载。相信很多小伙伴已经知道图片懒加载是怎么实现的,它

作者站长头像
站长
· 阅读数 46

前言

今天我们聊聊前端性能优化系列之图片预加载。相信很多小伙伴已经知道图片懒加载是怎么实现的,它的核心思想就是利用占位图这么一个操作,当图片到达视口时,将占位图换成真实的图片地址,具体怎么判断图片到达视口可以利用监听滚动事件或者利用intersectionObserver进行判断。现在我们换一种方式来进行图片加载的优化,利用webworker技术来进行优化。

js是单线程吗?

在聊图片预加载之前,咱们先聊聊js是单线程吗这个话题。在没有 Web Worker 技术之前,JavaScript 在浏览器环境中一直是单线程的。 JavaScript 设计成单线程执行是为了避免复杂性并简化对 Web 页面状态的一致性管理,尤其是考虑到对 DOM(文档对象模型)的访问和修改。所以在书写HTML代码时我们一般将script标签放在body的底部,这是因为js的加载和执行会阻塞html的渲染,为了先渲染Ui,js代码一般放在最底部。

但是当我们利用cdn的方式引入vue的源码时一般是放在head标签里面的,难道他就不会阻塞吗?其实它也会,那么我们有没有办法优化呢?有,我们可以在script标签里面添加async属性,让js的加载变成异步,浏览器在加载js的时候,不会阻塞html的渲染,但是执行js代码还是会阻塞html的渲染。或者使用defer属性,让js的加载变成异步并且延迟执行js,等到html的解析完成之后再执行js代码,这里的js代码指的是vue源码。

webworker

Web Worker 是一种浏览器技术,它允许在 Web 应用程序中执行 JavaScript 脚本而不会干扰用户界面的性能。它提供了一个独立的线程来处理一些耗时的任务,这意味着它们可以在后台运行而不干扰到网页的其他部分。这样可以提高应用程序的性能和用户体验。

所以我们可以利用这个机制来对我们的图片进行一个预加载的功能。webworker他会涉及到主线程和子线程的一个通信,主要是通过postMessage`和 onmessage来进行传输。

图片预加载

主要思想

我们在主线程中创建一个子线程,让子线程去请求我们的图片资源,子线程将请求回来的图片资源发送给主线程。主线程接收到后将图片资源渲染到页面上。

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <h2>图片预加载</h2>
        <div id="pic"></div>
    </div>
    <script>
        let picBox = document.getElementById("pic");
        let arr = [
            "https://picsum.photos/200/300?random=1",
            "https://picsum.photos/200/300?random=2",
            "https://picsum.photos/200/300?random=3",
            "https://picsum.photos/200/300?random=4",
            "https://picsum.photos/200/300?random=5",
            "https://picsum.photos/200/300?random=6",
            "https://picsum.photos/200/300?random=7",
            "https://picsum.photos/200/300?random=8",
            "https://picsum.photos/200/300?random=9",
            "https://picsum.photos/200/300?random=10"
        ]
        // 创建worker线程
        const worker = new Worker('./image.js');
        worker.postMessage(arr);
        // 监听父线程的消息
        worker.onmessage = function (e) {
            const img = new Image();
            img.src = window.URL.createObjectURL(e.data);
            img.onload = function () {
                picBox.appendChild(img);
            }
        }
    </script>
</body>

</html>

image.js

self.onmessage = function(e){
    console.log(e.data);
    let arr = e.data;
    for(let i=0;i<arr.length;i++){
      let xhr = new XMLHttpRequest();
      xhr.open('GET',arr[i],true);
      xhr.responseType = 'blob';
      xhr.onreadystatechange = function(){
        if(xhr.readyState==4&&xhr.status==200){
            self.postMessage(xhr.response);
        }
      }
      xhr.send();
    }
}

这里需要注意的一点就是我们需要将子线程传过来的图片文件对象Blob转成URL地址,这里我们使用window.URL.createObjectURL这个api进行转换。

转载自:https://juejin.cn/post/7413541435331690559
评论
请登录