做影视网站,电子商务网站费用预算,怎样申请做自己的网站,辽阳网站开发背景
js是单线程这是大家都知道#xff0c;为了防止多个线程同时操作DOM#xff0c;这个导致一个复杂的同步问题。比如#xff0c;假定JavaScript同时有两个线程#xff0c;一个线程在某个DOM节点上添加内容#xff0c;另一个线程删除了这个节点#xff0c;这时浏览器应…背景
js是单线程这是大家都知道为了防止多个线程同时操作DOM这个导致一个复杂的同步问题。比如假定JavaScript同时有两个线程一个线程在某个DOM节点上添加内容另一个线程删除了这个节点这时浏览器应该以哪个线程为准。
webWorker
web worker是 HTML5 标准的一部分这一规范定义了一套 API允许我们在 js 主线程之外开辟新的 Worker 线程并将一段 js 脚本运行其中它赋予了开发者利用 js 操作多线程的能力。
因为是独立的线程Worker 线程与 js 主线程能够同时运行互不阻塞。所以在我们有大量运算任务时可以把运算任务交给 Worker 线程去处理当 Worker 线程计算完成再把结果返回给 js 主线程。这样js 主线程只用专注处理业务逻辑不用耗费过多时间去处理大量复杂计算从而减少了阻塞时间也提高了运行效率页面流畅度和用户体验自然而然也提高了。
常见问题
场景一人脸识别和活体检测
在这两个场景中会通过ws实时上传图片加密
这里面主要是两个问题 1图片加密频繁操作导致占用主线程页面出现卡顿卡死情况
2定时器延时上面操作导致定时器并不是开始规定的5秒可能是7秒8秒
场景二大规模数据上传
比如有个项目前端拿到很大量据需要需要后处理后再上传服务器。
处理数据可能会占用主线程导致页面显示不流程卡顿等情况
场景三请求过于频繁读写操作过多
同上
场景四视频音频转码、转格式、加密等操作。
和场景一一样大量耗费计算资源。阻塞主线程导致页面流畅度下降响应降低。
解决以上问题可以考虑使用webwork
怎么使用
要使用先了解它 Web Worker的限制 1、在 Worker 线程的运行环境中没有 window 全局对象也无法访问 DOM 对象。 2、Worker中只能获取到部分浏览器提供的 API如定时器、navigator、location、XMLHttpRequest等。 3、由于可以获取XMLHttpRequest 对象可以在 Worker 线程中执行ajax请求。 4、每个线程运行在完全独立的环境中需要通过postMessage、 message事件机制来实现的线程之间的通信。 worker.postMessage: 向 worker 的内部作用域发送一个消息消息可由任何 JavaScript 对象组成 worker.terminate: 立即终止 worker。该方法并不会等待 worker 去完成它剩余的操作worker 将会被立刻停止 worker.onmessage: 当 worker 的父级接收到来自其 worker 的消息时会在 Worker 对象上触发message 事件 worker.onerror: 当 worker 出现运行中错误时它的 onerror事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error 的事件 我直接上代码我常用不,是只会vue看在项目是怎么使用的。
我写了几个worker.js 1msg.worker.js 为了消息推送 onmessage function(e) {console.log(e)postMessage(e.data.num);// close();
}import MsgWorker from ./demo/msg.worker; // mounted 初始化
this.msgWorker new MsgWorker ();this.worker.onmessage (event) {console.log(event.data);this.result event.data;console.log(主线程收到回复即将关闭worker连接, this.index);// this.worker.terminate();
};methods: {useWorker() {this.msgWorker.postMessage({ text: 当前时间, num: Date.now() });},},想想他能干嘛? 利用策略模式全局监听操作和vue Bus 功能一样使用在页面交互功能一样。 有人说和写个全局方法不一样吗 不一样它不占用js的主线程 2time.worker.js添加定时器 onmessage function (e) {setTimeout(() {postMessage(Date.now());}, e.data.time);// close();
}; import TimeWorker from ./demo/time.worker;//初始化mounted
mounted() {this.timeWorker new TimeWorker();this.timeWorker.onmessage (event) {this.result event.data;console.log(定时完成);};},
//方法调用methods: {useWorker() {this.timeWorker.postMessage({ time: 10000 });},}, 定时器能干嘛如果进来先执行 上面定时器useWorker() 再执行下面计算demo 它能定时输出时间不被js主线程阻塞影响。 demo() {console.log(Start, Date.now());let i 0;for (let index 0; index 100000000000; index) {i index;}console.log(i, Date.now())console.log(End, Date.now());
} 3canvas.worker.js canvas绘制 templatediv classcanvas-demobutton clickmakeWorker开始绘图/buttoncanvas idmyCanvas width300 height150/canvas/div
/templatescript
import Worker from ./demo/canvas.worker;export default {methods: {makeWorker() {let worker new Worker();let htmlCanvas document.getElementById(myCanvas);// 使用canvas的transferControlToOffscreen函数获取一个OffscreenCanvas对象let offscreen htmlCanvas.transferControlToOffscreen();// 注意第二个参数不能省略worker.postMessage({ canvas: offscreen }, [offscreen]);}}
};
/scriptstyle langless
.canvas-demo {padding: 20px;
}
/style canvas.worker.js onmessage function (e) {// 使用OffscreenCanvas离屏Canvaslet canvas e.data.canvas;// 获取绘图上下文let ctx canvas.getContext(2d);// 绘制一个圆弧ctx.beginPath(); // 开启路径ctx.arc(150, 75, 50, 0, Math.PI * 2);ctx.fillStyle #333333; //设置填充颜色ctx.fill(); //开始填充ctx.stroke();
};4xhrWorker.js接口调用 templatedivbutton clickuseWorker开始线程/button/div
/templatescript
import { fetchApi} from ./demo/xhrWorker.js;
export default {data() {return {worker: null,};},mounted() {const blob fetchApi();this.worker new Worker(blob); // 使用上面import进来的js名字为 demo.worker.worker.js不可配置路径相对比较灵活需要worker-loaderthis.worker.onmessage (event) {console.log(event.data);console.log(主线程收到回复即将关闭worker连接, event.data);// this.worker.terminate();};this.worker.onerror (event) {console.log(event.data);};},methods: {useWorker() {this.worker.postMessage({url: http://xx.xx.xx.xx:8888/login,data: {password: admin,username: admin123456,},responseType: json,method: POST,id: Date.now(),});},},// 页面关闭如果还没有计算完成要销毁对应线程beforeDestroy() {},
};
/scriptxhrWorker.js 我尝试将他写成 xhr.worker.js 结果获取不到fetchApi方法可以注意下 export function fetchApi() {const workerCode
self.addEventListener(message, async function (e) {const { url, data, responseType, method, id } e.dataconst xhr new XMLHttpRequest()xhr.open(method, url, true)xhr.responseType responseTypexhr.setRequestHeader(Content-Type, application/json)xhr.onload function () {if (xhr.status 200) {self.postMessage({xhrRes: xhr.response, id})} else {self.postMessage({ error: error })}}xhr.onerror function () {self.postMessage({ error: error })}xhr.send(JSON.stringify(data))
})
const blob new Blob([workerCode], { type: application/javascript })const blobUrl URL.createObjectURL(blob)return blobUrl
}5dataWorker.js数据计算 templatedivdiv classdata-lsitdiv classdata-item vspan数据/span/div/divbutton clickmakeWorker开始线程/button!--在计算时 往input输入值时 没有发生卡顿--pinput typetext //p/div
/templatescript
import Worker from ./demo/math.worker;export default {data() {// 模拟数据let arr new Array(20).fill(1).map(() Math.random() * 10000);let weightedList new Array(100000).fill(1).map(() Math.random() * 10000);let calcList [{ type: sum, name: 总和 },{ type: average, name: 算术平均 },{ type: weightedAverage, name: 加权平均 },{ type: max, name: 最大 },{ type: middleNum, name: 中位数 },{ type: min, name: 最小 },{ type: variance, name: 样本方差 },{ type: popVariance, name: 总体方差 },{ type: stdDeviation, name: 样本标准差 },{ type: popStandardDeviation, name: 总体标准差 },];return {workerList: [], // 用来存储所有的线程calcList, // 计算类型arr, // 数据weightedList, // 加权因子};},methods: {makeWorker() {this.calcList.forEach((item) {let workerName worker${this.workerList.length};let worker new Worker();let start performance.now();worker.postMessage({arr: this.arr,type: item.type,weightedList: this.weightedList,});worker.addEventListener(message, (e) {worker.terminate();let tastName ;this.calcList.forEach((item) {if (item.type e.data.type) {item.value e.data.value;tastName item.name;}});let end performance.now();let duration end - start;console.log(当前任务: ${tastName}, 计算用时: ${duration} 毫秒);});this.workerList.push({ [workerName]: worker });});},clearWorker() {if (this.workerList.length 0) {this.workerList.forEach((item, key) {item[worker${key}].terminate item[worker${key}].terminate(); // 终止所有线程});}},},// 页面关闭如果还没有计算完成要销毁对应线程beforeDestroy() {this.clearWorker();},
};
/scriptimport { create, all } from mathjs
const config {number: BigNumber,precision: 20 // 精度
}
const math create(all, config);//加
const numberAdd (arg1,arg2) {return math.number(math.add(math.bignumber(arg1), math.bignumber(arg2)));
}
//减
const numberSub (arg1,arg2) {return math.number(math.subtract(math.bignumber(arg1), math.bignumber(arg2)));
}
//乘
const numberMultiply (arg1, arg2) {return math.number(math.multiply(math.bignumber(arg1), math.bignumber(arg2)));
}
//除
const numberDivide (arg1, arg2) {return math.number(math.divide(math.bignumber(arg1), math.bignumber(arg2)));
}// 数组总体标准差公式
const popVariance (arr) {return Math.sqrt(popStandardDeviation(arr))
}// 数组总体方差公式
const popStandardDeviation (arr) {let s,ave,sum 0,sums 0,len arr.length;for (let i 0; i len; i) {sum numberAdd(Number(arr[i]), sum);}ave numberDivide(sum, len);for(let i 0; i len; i) {sums numberAdd(sums, numberMultiply(numberSub(Number(arr[i]), ave), numberSub(Number(arr[i]), ave)))}s numberDivide(sums,len)return s;
}// 数组加权公式
const weightedAverage (arr1, arr2) { // arr1: 计算列arr2: 选择的权重列let s,sum 0, // 分子的值sums 0, // 分母的值len arr1.length;for (let i 0; i len; i) {sum numberAdd(numberMultiply(Number(arr1[i]), Number(arr2[i])), sum);sums numberAdd(Number(arr2[i]), sums);}s numberDivide(sum,sums)return s;
}// 数组样本方差公式
const variance (arr) {let s,ave,sum 0,sums 0,len arr.length;for (let i 0; i len; i) {sum numberAdd(Number(arr[i]), sum);}ave numberDivide(sum, len);for(let i 0; i len; i) {sums numberAdd(sums, numberMultiply(numberSub(Number(arr[i]), ave), numberSub(Number(arr[i]), ave)))}s numberDivide(sums,(len-1))return s;
}// 数组中位数
const middleNum (arr) {arr.sort((a,b) a - b)if(arr.length%2 0){ //判断数字个数是奇数还是偶数return numberDivide(numberAdd(arr[arr.length/2-1], arr[arr.length/2]),2);//偶数个取中间两个数的平均数}else{return arr[(arr.length1)/2-1];//奇数个取最中间那个数}
}// 数组求和
const sum (arr) {let sum 0, len arr.length;for (let i 0; i len; i) {sum numberAdd(Number(arr[i]), sum);}return sum;
}// 数组平均值
const average (arr) {return numberDivide(sum(arr), arr.length)
}// 数组最大值
const max (arr) {let max arr[0]for (let i 0; i arr.length; i) {if(max arr[i]) {max arr[i]}}return max
}// 数组最小值
const min (arr) {let min arr[0]for (let i 0; i arr.length; i) {if(min arr[i]) {min arr[i]}}return min
}// 数组有效数据长度
const count (arr) {let remove [, , null , undefined, -]; // 排除无效的数据return arr.filter(item !remove.includes(item)).length
}// 数组样本标准差公式
const stdDeviation (arr) {return Math.sqrt(variance(arr))
}// 数字三位加逗号保留两位小数
const formatNumber (num, pointNum 2) {if ((!num num ! 0) || num -) return --let arr (typeof num string ? parseFloat(num) : num).toFixed(pointNum).split(.)let intNum arr[0].replace(/\d{1,3}(?(\d{3})(.\d*)?$)/g,$,)return arr[1] undefined ? intNum : ${intNum}.${arr[1]}
}onmessage function (e) {let {arr, type, weightedList} e.datalet value ;switch (type) {case sum:value formatNumber(sum(arr));breakcase average:value formatNumber(average(arr));breakcase weightedAverage:value formatNumber(weightedAverage(arr, weightedList));breakcase max:value formatNumber(max(arr));breakcase middleNum:value formatNumber(middleNum(arr));breakcase min:value formatNumber(min(arr));breakcase variance:value formatNumber(variance(arr));breakcase popVariance:value formatNumber(popVariance(arr));breakcase stdDeviation:value formatNumber(stdDeviation(arr));breakcase popStandardDeviation:value formatNumber(popStandardDeviation(arr));break}// 发送数据事件postMessage({type, value});
}总结
以上列子分了五个场景直接引入项目就可以测试最后一个例子请参考一文彻底了解Web Worker十万条数据都是弟弟附带源码。
写这篇文章为了巩固下webWorker的使用希望能对你们有所帮助如果有帮助请点个赞。谢了