欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > webWorker的概念 用法 场景

webWorker的概念 用法 场景

2025/3/10 6:38:08 来源:https://blog.csdn.net/m1011815213/article/details/145948959  浏览:    关键词:webWorker的概念 用法 场景

这里引用上个文章的图片 这里学习下 webWorker

<template><div><div style="display: flex; justify-content: center; align-items: center; margin-top: 20px;"><div class="image-container"><img src="https://i.imgur.com/cCWBPHi.png" class="final-image"></div><div class="image-container"><!-- 使用 v-show 确保 canvas 元素始终存在 --><canvas v-show="!isComplete" ref="canvasRef" class="canvas" /><img v-show="isComplete" :src="finalImageData" alt="加载完成的图片" class="final-image"></div></div></div>
</template><script setup>
import { onMounted, ref } from 'vue'// 定义变量
const canvasRef = ref(null) // canvas 元素引用
const loading = ref(false) // 加载状态
const error = ref(false) // 错误状态
const isComplete = ref(false) // 是否加载完成
const finalImageData = ref('') // 最终图片的 Base64 数据// 创建 Worker 实例
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })// 监听 Worker 的消息
worker.onmessage = function (event) {const { type, data } = event.dataif (type === 'progress') {console.log(`当前分片高度: ${data.chunkHeight}px, 当前绘制位置: y = ${data.y}px`)}else if (type === 'complete') {console.log('图片加载完成!')finalImageData.value = data.imageDataisComplete.value = trueloading.value = falseworker.terminate() // 释放 Worker 主线程资源}else if (type === 'error') {console.error('加载图片失败:', data.message)error.value = trueloading.value = false}
}// 点击按钮加载图片
function loadImage() {// 确保 canvas 元素已经渲染if (!canvasRef.value) {console.error('canvas 元素未渲染')return}// 将 canvas 的控制权转移到 OffscreenCanvas// OffscreenCanvas 是 HTML5 提供的一个 API,它允许你将 canvas 的渲染操作放到主线程之外的上下文中执行(例如 Web Worker),从而避免阻塞主线程,提升性能const offscreenCanvas = canvasRef.value.transferControlToOffscreen()// 发送任务给 Workerworker.postMessage({canvas: offscreenCanvas,url: 'https://i.imgur.com/cCWBPHi.png',chunkSize: 100,},[offscreenCanvas],)loading.value = trueerror.value = false
}// 在 onMounted 钩子中调用 loadImage,确保 DOM 已渲染
onMounted(() => {loadImage()
})
</script><style lang="scss" scoped>
.image-container {display: flex;justify-content: center;align-items: center;margin-top: 20px;
}.canvas {border: 1px solid #ccc;max-width: 100%;max-height: 80vh;/* 限制 canvas 的最大高度 */
}.final-image {max-width: 100%;max-height: 80vh;/* 限制图片的最大高度 */border: 1px solid #ccc;
}
</style>

下面是 worker.js 文件

其实通信原理和 iframe 一样 只不过可以开启多线程

// 监听主线程的消息  这里的self也就是主线程的window对象
self.onmessage = async function (event) {const { canvas, url, chunkSize } = event.datatry {// 加载图片const response = await fetch(url)const blob = await response.blob()const img = await createImageBitmap(blob)// 设置 canvas 尺寸const width = img.widthconst height = img.heightcanvas.width = widthcanvas.height = heightconst ctx = canvas.getContext('2d')// 分片加载逻辑let y = 0 // 初始化 y 坐标,表示当前绘制的位置const loadNextChunk = function () {// 计算当前分片的高度const chunkHeight = Math.min(chunkSize, height - y)// 绘制当前分片ctx.drawImage(img, 0, y, width, chunkHeight, 0, y, width, chunkHeight)y += chunkHeight // 更新 y 坐标,准备绘制下一个分片// 发送进度信息给主线程self.postMessage({type: 'progress',data: { chunkHeight, y },})// 如果未加载完,继续加载下一个分片if (y < height) {requestAnimationFrame(loadNextChunk) // 使用 requestAnimationFrame 优化渲染}else {// 加载完成,将 canvas 转换为图片并发送给主线程canvas.convertToBlob().then((blob) => {const reader = new FileReader()reader.readAsDataURL(blob)reader.onloadend = function () {self.postMessage({type: 'complete',data: { imageData: reader.result },})}})}}// 开始加载第一个分片loadNextChunk()}catch (e) {console.error('加载图片失败:', e)self.postMessage({type: 'error',data: { message: e.message },})}
}

今天,我在学习Web Workers的时候,遇到了一些概念,感觉有点复杂。我决定仔细研究一下,看看能不能理解清楚。

首先,我知道Web Workers是一种在后台线程中运行JavaScript代码的方法,可以用来处理复杂的计算任务,从而不阻塞主线程,提升用户体验。但具体的实现方式,我还不太清楚。

我看到代码中使用了new Worker()方法来创建一个Web Worker。这让我想到,是不是在主线程中创建了一个新的线程,专门用来处理特定的任务?好像是这样。然后,主线程通过worker.postMessage()方法向Worker发送任务。这让我联想到Vue.js中父组件和子组件之间的通信,父组件通过$emit方法向子组件传递数据,而子组件通过事件监听来接收数据。难道这里也是类似的机制?

于是,我查找了一些资料,发现确实,postMessage方法在主线程和Worker之间传递数据,就像组件之间的事件传递一样。主线程发送消息,Worker接收并处理,然后通过self.postMessage()将结果发送回去。这确实有点像Vue2中的父子传值,只不过这里的“子”是Worker线程。

接下来,我看到在主线程中使用了worker.onmessage来监听Worker的消息。这部分有点让我困惑。我想,onmessage是不是一种事件监听器,当Worker发送消息回来时,主线程就能接收到并处理?这和Vue中的事件处理很像,父组件监听子组件的事件,当子组件触发事件时,父组件执行相应的处理函数。

为了更好地理解,我尝试写了一个简单的例子。主线程创建一个Worker,然后通过postMessage发送一个计算任务,Worker接收到任务后进行计算,然后通过postMessage把结果送回主线程。主线程监听到消息后,处理结果并显示出来。运行后,发现确实有效,计算任务在后台线程完成,主线程继续处理其他事情。

但是,我也有疑问。比如,Worker和主线程之间的通信是不是只能通过postMessage?有没有其他方式?另外,self在Worker中的作用是什么?为什么不能用this或者其他变量?

我查阅了相关文档,了解到在Worker中,self是指向Worker全局对象的,可以用它来发送和接收消息。而主线程和Worker之间的通信只能通过postMessage方法,这是为了确保线程安全,避免共享内存带来的问题。

还有一个问题,如果主线程和Worker之间传递的是对象,会发生什么?会不会导致数据共享的问题?文档中提到,传递的是结构化克隆,而不是引用,因此不会共享内存,每个线程都有自己的数据副本,这样就避免了竞态条件和数据不一致的问题。

通过这个学习过程,我对Web Workers有了更深入的理解,特别是它们和Vue组件之间的类比,帮助我更好地记忆和应用这些概念。虽然有些细节还需要进一步探索,但总体上,我觉得自己已经掌握了一个基本的框架。

总结:
使用 new Worker() 方法在主线程创建了一个 Web Worker,主线程通过 worker.postMessage() 发送任务给 Worker,并在主线程开启 worker.onmessage 监听 Worker 的消息。这与 Vue2 中的父子组件通信机制相似,主线程类似于父组件,Worker 线程类似于子组件。Worker.js 文件中通过 self.postMessage() 将结果发送回主线程,主线程在接收到消息后进行处理。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词