什么是web work

js采用的是单线程模型,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力

相对的webwork就是为js创造多线程的环境,允许主线程创建webwork线程,将未处理的一些任务分给后者 运行.在js主线程运行的同时,work线程在后台运行,两者互不打扰,等到webwork线程的任务结束后,把结果返回给主线程

web work的注意点

(1) 同源限制:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2) DOM限制:Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
(3) 通信联系:Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成
(4) 脚本限制:Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

(5) 文件限制: Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

在Vue中使用 web work

1.安装worker-loadernpm install worker-loader

2.编写worker.js文件

onmessage = function (e) {// onmessage获取传入的初始值let sum = e.data;for (let i = 0; i < 200000; i++) {for (let i = 0; i < 10000; i++) {sum += Math.random()}}// 将计算的结果传递出去postMessage(sum);
}

3.通过行内loader引入worker.js  import Worker from 'worker-loader!./worker'

4.完整代码

<template><div><button @click="makeWorker">开始线程</button><!--在计算时 往input输入值时 没有发生卡顿--><p><input type="text"></p></div>
</template><script>import Worker from "worker-loader!./worker";export default {methods: {makeWorker() {// 获取计算开始的时间let start = performance.now();// 新建一个线程let worker = new Worker();// 线程之间通过postMessage进行通信worker.postMessage(0);// 监听message事件worker.addEventListener("message", (e) => {// 关闭线程worker.terminate();// 获取计算结束的时间let end = performance.now();// 得到总的计算时间let durationTime = end - start;console.log('计算结果:', e.data);console.log(`代码执行了 ${durationTime} 毫秒`);});}},}
</script>

计算过程中,页面就不会发生卡顿

开启多线程,并进行计算

回到要解决的问题执行多种运算时,给每种运算开启单独的线程,线程计算完成后要及时关闭

<template><div><button @click="makeWorker">开始线程</button><!--在计算时 往input输入值时 没有发生卡顿--><p><input type="text"></p></div>
</template><script>import Worker from "worker-loader!./worker";export default {data() {// 模拟数据let arr = new Array(100000).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();},}
</script>

worker.js中代码

import { 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.length+1)/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});
}

此时数据加载时间会由原来的35s变成6s

Web Worker的限制

1、在 Worker 线程的运行环境中没有 window 全局对象,也无法访问 DOM 对象

2、Worker中只能获取到部分浏览器提供的 API,如定时器navigatorlocationXMLHttpRequest

3、由于可以获取XMLHttpRequest 对象,可以在 Worker 线程中执行ajax请求

4、每个线程运行在完全独立的环境中,需要通过postMessage、 message事件机制来实现的线程之间的通信

JavaScript 中的多线程 -- Web WorkerOffscreenCanvas-离屏canvas使用说明

参考链接:如何让前端拥有后端的计算能力?一文彻底了解Web Worker - 掘金

对webwork的理解与使用相关推荐

  1. Webwork 学习之路【08】结合实战简析Controller 配置

    虽然现在 MVC 框架层出不穷,但做为 Struts 前身的 webwork. 其经典程度不亚于贝利之于足球,双 11 之于淘宝特卖. 本篇将结合 webwork controller 配置文件 xw ...

  2. java web入门——概念理解、名词解释

    引言:当你想入门java web后,一定会查阅到很多相关的名词:Servlet,HTML,Spring...等等之类的,但是对于他们之间的关系总是比较混乱的,这篇文章就是理清这些名词的关系. 什么是w ...

  3. 深入理解Struts2

    简单介绍 Struts 2是Struts的下一代产品.是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架. 其全新的Struts 2的体系结构与Struts 1的 ...

  4. (转自http://www.blogjava.net/moxie/archive/2006/10/20/76375.html)WebWork深入浅出

    (转自http://www.blogjava.net/moxie/archive/2006/10/20/76375.html) WebWork深入浅出 本文发表于<开源大本营> 作者:钱安 ...

  5. js定时器异步请求时候 上一个请求没有响应时下一个请求已经开始_关于异步的理解...

    这里只是个人的理解,用于理解+笔记,记录对异步的粗糙理解. --写在前面 异步的情景: 一:异步的出现场景可分为以下 1. Ajax请求数据时 2. 定时器 3. 一些点击事件(这里暂时了解的不是特清 ...

  6. WebWork教程一

    WebWork介绍 WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的拉出式MVC模式J2EE Web框架.WebWork目前最新版本是2.1,现在的WebWork2.x前 ...

  7. 一个同行对JAVA的理解

    想来学习Java也有两个年头了,永远不敢说多么精通,但也想谈谈自己的感受,写给软件学院的同仁们,帮助大家在技术的道路上少一点弯路.说得伟大一点是希望大家为软件学院争气,其实最主要的还是大家自身的进步提 ...

  8. webwork简单示例

    webwork是struts2的前身,是一个mvc框架,使用方法和struts2很相似.研究webwork已经没有太大的意义,但是对于理解struts2的核心机制还是有一定意义的.下面介绍如何通过we ...

  9. 通用解题法——回溯算法(理解+练习)

    积累算法经验,积累解题方法--回溯算法,你必须要掌握的解题方法! 什么是回溯算法呢? 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就&quo ...

最新文章

  1. 工业级路由器和家用路由器的区别_5G工业级路由器有哪些优势
  2. java编程实现素数环_结对编程(JAVA实现)
  3. Android Studio 无法浏览插件市场
  4. 专访 openEuler 江大勇:对美好的向往就是越有能力越开放
  5. c# mvc如何生成excel
  6. 中文文本校对源码java_文字校对应该怎么校对?
  7. matlab 实现批量修改文件后缀名 案例
  8. 开发直播APP时,视频图片等上传到七牛云存储的实现流程
  9. Cesium 角度计算
  10. 文化袁探索专栏——Activity|Application启动流程
  11. 列出一些既好玩又能提高英语水平的电脑游戏
  12. 试验设计类毕业论文文献有哪些?
  13. 利用7z程序压缩、解压
  14. BootstrapTable之千分位分隔符设置
  15. F2FS源码分析-6.6 [其他重要数据结构以及函数] F2FS的重命名过程-f2fs_rename函数
  16. 百度云盘搜索引擎微信公证号_微信公众号被百度搜索引擎收录?SEO优化诞生新方法!...
  17. 分布式光纤测温系统DTS-BLY-5S
  18. 电脑桌面便签如何按农历日历设置便签提醒事项?
  19. 计算机声音打不开怎么办,电脑声音打不开怎么办
  20. 股票购买接口委托下单c++代码

热门文章

  1. 【layui】layui table表格换行多列 一页样式 css样式
  2. 人工智能ai算法_AI算法和联邦贸易委员会
  3. 辗转相除法(求两个非负整数的最大公约数)(拓展:求n个非负整数的最大公约数)
  4. 微信公众号广告平台服务器,微信公众号的与众不同,从第三方平台开始
  5. 『ML笔记』HOG特征提取原理详解+代码
  6. 台式计算机通讯串口在哪,串口通讯
  7. html5用代码实现页面跳转页面跳转,H5上滑跳转页面的实现(代码实例)
  8. 算法与数据结构(六) 迪杰斯特拉算法的最短路径(Swift版)
  9. _get_sysconfigdata_name() missing 1 required positional argument: ‘check_exists‘
  10. [图解]无光驱,无软驱,你可以这样重装系统