运营:别再让你的页面一直loading 了
点击关注公众号,“技术干货”及时达!
运营:别再让你的页面一直loading 了May-17-2024 15-36-38.gif第一轮 battle
Q:我想下载一个大文件,界面一直转圈,很耽误时间,我想在下载的时候还做点其他事情
A:一直转圈就一直等呗,反正还能摸会(奈何小姐姐太想做牛马了)
第二轮 battle
Q:不行,为什么别人的浏览器,下载软件/文件 就能操作界面,你这就一直转圈,什么都做不了
A:我们js 是单线程,一个时间只能做一件事,你不能在下载文件的时候,还操作界面吧...逐渐语无伦次,行,我给你试着优化优化..
image.png最终效果
save.gif无敌.gif可以看到,下载文件 页面不再转圈,并且可以在界面操作,但是在点击操作1,2,到3的时候,会卡顿一下,下面会说为什么会卡这一下
开始分析执行文件下载操作,把转圈逻辑去掉不就行了,but:是不转圈了,下载的时候,依然操作不了界面
js 是一个单线程,一个时间只能做一件事,密集的cpu 计算,导致网站反应迟钝,就像卡了一样resolve:把下载文件这个耗时操作,放在其他线程操作,等到操作完毕,再通知主线程,执行完了。就像发布订阅模式一样,主线程不用执行密集的计算,也不用特意等密集计算的结果,执行完,告诉我就行了
技术使用 Web Workers摘自 MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers#web_workers_api
Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,它们可以使用XMLHttpRequest(尽管responseXML和channel属性总是为空)或fetch(没有这些限制)执行 I/O。一旦创建,一个 worker 可以将消息发送到创建它的 JavaScript 代码,通过将消息发布到该代码指定的事件处理器(反之亦然)。
为什么要用它:worker 的一个优势在于能够执行处理器密集型的运算
而
「不会阻塞 UI 线程」
「不会阻塞 UI 线程」
「不会阻塞 UI 线程」
「不会阻塞 UI 线程」
重要的事情说三遍 ????????????????????????????????????????????
基本使用主线程生成一个专用 workerconst myWorker = new Worker("worker.js"); // worker.js 是一个脚本的 URI 来执行 worker 线程
专用 worker 中消息的接收和发送就俩主要方法 postMessage onmessage
引入脚本与库Worker 线程能够访问一个全局函数importScripts()来引入脚本,该函数接受 0 个或者多个 URI 作为参数来引入资源;以下例子都是合法的:
importScripts();/*什么都不引入*/
importScripts("foo.js");/*只引入"foo.js"*/
importScripts("foo.js","bar.js");/*引入两个脚本*/
importScripts("//example.com/hello.js");/*你可以从其他来源导入脚本*/
ESModule 模式constworker=newWorker('worker.js',
{type:'module'//指定worker.js的类型}
文件下载代码baseCodeimport{writeFile,utils}from'xlsx'
/**模拟生成大文件数据*/
constgenerateLargeFileData=()={
constdata=[]
for(leti=0;i10000;i++){
data.push({
id:i+1,
name:`User${i+1}`,
email:`user${i+1}@example.com`,
age:Math.floor(Math.random()*100)+1
})
}
returndata
}
一只转圈的代码/**下载大文件*/
constdownloadExcel=async()={
//模拟生成大文件数据
constdata=generateLargeFileData()
loading.value=true
//模拟一段短暂的等待时间,确保状态更新
awaitdelay(1000)
//卡死的罪魁祸者
//将数据转换为Excel格式
constws=utils.json_to_sheet(data)
constwb=utils.book_new()
utils.book_append_sheet(wb,ws,'Sheet1')
writeFile(wb,'test.xlsx')
loading.value=false
}
使用webworker,将耗时计算放到 webworker 线程,解决阻塞ui的问题主线程
constmyWorker=newWorker('downloadWorker.js')
myWorker.onmessage=(event)={
letwb=event.data
//这里也会占用主线程的ui渲染,所以会卡一下
writeFile(wb,'test.xlsx')
ElMessage.success('下载任务已在后台运行,可以继续操作界面其他任务')
}
/**下载大文件*/
constdownloadExcel=async()={
constdata=generateLargeFileData()
myWorker.postMessage(data)
}
worker 线程
image.png//非模块化文件,public打包本身就是线上文件了
importScripts("./xlsx.js");//线上地址,或者本地地址
self.onmessage=(e)={
//将数据转换为Excel格式
constws=XLSX.utils.json_to_sheet(e.data)
constwb=XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb,ws,'Sheet1')
//writeFile(wb,'test.xlsx')//这里会操作dom,所以将操作dom放到主线程做
self.postMessage(wb)
self.close()
}
细节补充本文主要介绍了专用worker,其实还有 共享 worker【主要做多页面标签通信】, ServiceWorkers 【主要做网络拦截,可以看一下之前写的pwa文章【https://juejin.cn/post/7062681470116036616】,离线缓存就是使用ServiceWorkers】
在主线程中使用时,onmessage和postMessage()必须挂在worker对象上,而在 worker 中使用时不用这样做。原因是,在 worker 内部,worker 是有效的全局作用域(就像window.xxx ,window 一般可以不写)
worker的关闭
//main.js(主线程)
constmyWorker=newWorker('/worker.js');//创建worker
myWorker.terminate();//关闭worker
//worker.js(worker线程)
self.close();//直接执行close方法就ok了
worker 错误监听 messageerror
关于主线程里的 new Worker('downloadWorker.js')
这个脚本,必须是本地/或者网络地址,这里写的是项目运行地址 匹配相应的worker。这里大家也会发现一个问题,就是这个worker是全局性的,放在public 是一个不错的选择,再者打包后,public 下本身也是会放在服务器上
用完worker, 要及时关闭,他是不会自己结束的。选择 在worker 关闭,或者主线程关闭,会有区别
其实小文件下载,用worker 有点画蛇添足,本身使用worker 也是一种消耗
详细的参考资料以及代码地址MDNhttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workershttps://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorkerhttps://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_APIMDN code仓库https://github.com/mdn/dom-examples可以下载下来直接调试,最好是起一个本地服务: http-server
image.png掘金https://juejin.cn/post/7139718200177983524https://juejin.cn/post/7345672631323115570#heading-15代码地址https://gitee.com/Big_Cat-AK-47/vue-project.git
??????番外 ????????????最近在做一个项目,主要技术栈是v3 + el-plus + axios + pinia + vite5 + UnoCSS, 就是上面的仓库地址,主要是总结平时做的亮点/难点。有志同道合的朋友,想一起code,欢迎滴滴我
目前打算做的模块
首页大屏数据可视化递归菜单/路由权限项目基建搭建大文件上传/断点续传/秒传/进度控制 以及一些优化手撸实现一个虚拟列表多语言/多主题 脚本编写《目前是在项目里,后期打算发布一个npm,包括封装常用方法,也会同步到npm》在线聊天项目工程化优化点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线