• 作者:老汪软件技巧
  • 发表时间:2024-09-17 15:03
  • 浏览量:

Web Workers

script中的async和defer

Web Workers可以为Web内容在后台线程中运行脚本提供了一种简单的方式,可以实现多线程.在进入到正文之前,我们先看一下这个问题,我们都知道js代码会阻塞html的渲染,那么我们如何解决呢?

html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js">script>
head>
<body>
    <div id="app">
        <h2>helloh2>
    div>
body>
html>

我们这里请求一份js资源,代码从上到下开始执行,最开始是浏览器的渲染引擎开始工作的,遇到script之后,V8引擎就会开始工作,浏览器渲染引擎就会终止工作,直到V8引擎工作结束,浏览器渲染引擎就继续工作.

那么这里我们有两种方式可以解决这个问题,一个是添加async属性,这一个属性会让js的加载变成异步,浏览器在加载js资源的同时会渲染html.

第二个就是添加defer属性,这个属性也是让js的加载变成异步,但是js资源加载完毕之后,不会立即执行js而是等待html渲染完毕之后再执行.

这里画一份简陋的图来表示

async和defer的共同点都是让js代码异步加载,但是对于async来说html渲染和js加载资源完毕并执行是同时进行的,而defer则是将js资源加载完毕后,等到html渲染完毕之后,js代码部分才会执行

正文

现在我们使用Web Workers来实现图片的预加载

html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<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"
        ]
        const worker = new Worker('./image.js')
        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>
html>

线程视图_多线程上传图片_

数组arr中存放的是我们需要预加载的图片.const worker = new Worker('./image.js')会为我们创建一个子线程.image.js脚本代码开辟一个新的线程.我们通过postMessage()方法将数组传给子线程.在子线程中我们需要获取到主线程传过来的参数.

self.onmessage = function(event){
    console.log(event);
}

self是一个全局对象,代表Worker自身,通过onmessage()监听信息,该方法接受事件参数event

我们在主线程传过来的数组的内容也就在事件参数中,我们可以通过event.data获取到该数组.我们获取到了该数组,也就代表着我们可以拿到图片对应的url地址.通过url加载图片.

for(let i = 0;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();
    }

我们通过for循环遍历数组event.data拿到url通过发送axios请求加载资源,xhr.responseType = 'blob'将图片资源加载成blob也就是加载成流的形式的文件.最后返回给主线.

worker.onmessage = function(event) {
            console.log('主线程:', event);
            const img = new Image()
            img.src = window.URL.createObjectURL(event.data)
            picBox.appendChild(img)
        }

在主线程中也是通过onmessage监听信息,拿到子线程处理过后的资源.

总结

Web Workers的工作流程其实也是非常的简单.通过new Workers创建Workers实例,在主线程中发送消息给子线程,子线程监听主线程消息,完成工作后.子线程将信息传给主线程,主线程监听子线程的信息,主线程拿到信息后再进行操作.简陋的流程图如下: