# 什么是 Web Worker
15 年前,也就是 2008 年, html
第五版 html5
发布,这一版的发布,提供了不少新的好用的功能,如:
- Canvas 绘图
- 拖拽 drag
- websocket
- Geolocation
- webworker
- 等...
笔者之前说过: 一项新技术新的技术方案的提出,一定是为了解决某个问题的,或者是对某种方案的优化
那么 Web Worker
这个新技术解决了什么问题?有哪些优化价值呢?
让我们继续往下看...
# 官方定义
Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用 XMLHttpRequest 执行 I/O (尽管 responseXML 和 channel 属性总是为空)。一旦创建,一个 worker 可以将消息发送到创建它的 JavaScript 代码,通过将消息发布到该代码指定的事件处理程序(反之亦然)......
官方 MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers
乍一看这段话,好像懂了( Web Worker和线程
有关),又好像没懂。但是我们能看到一个加粗的关键字:线程。
那么,新的问题来了, 什么是线程?
当我们去学习一个知识点
A
的时候,我们会发现知识点 A 是由a1、a2、a3、a4
组合而成的,所以我们要继续下钻,去搞懂a1、a2、a3、a4
分别是什么意思。这样才能更好的理解知识点A
的含义内容。
# 什么是线程
线程
基本八股文定义不赘述,大家可以将 线程
理解成为一个打工仔,每天的工作就是 解析翻译并执行代码
,像搬砖一样,不过一次只能搬一块砖,后面有砖,不好意思,你等会儿,等我把这个砖搬完了再搬你们。
线程道人朗声道:尔等砖头列队稍后,待老夫一块块搬!( js中的任务队列
)
js
是单线程语言
,生来便是!java
平常写代码也是单线程的操作
,不过单线程
有时候不太够用,于是java
中也提供了多线程
的操作入口,比如:Thread类
,Runnable接口
,Callable接口
;大多数语言都是类似的,python
也是的啊,python
写代码平常也是单线
程,另也提供了threading模块
让程序员可以去做多线程操作
。
# 为何 js 要设计成单线程呢?
- 符合大致趋势
- 这与
js
的工作内容有关:js
只是用来去做一些用户交互,并呈现效果内容。 - 试想,如果 js 是多线程,线程一将
dom元素
的背景色改成红色,线程二将dom元素
的背景色改为绿色,那么,到底上红色还是绿色呢? - 不过后来人们发现,某些情况下,
前端如果能做多线程的操作
,将会大大提升开发效率 - 于是
Web Worker
就应运而生了 Web Worker
可以创建另外的线程去做一些操作,操作不影响js
主线程(比如UI渲染
)- 本来只有一个
js主线程
搬砖,现在又过来好几个js辅助线程
一块帮忙搬砖,那肯定效率高啊!
有点道友问,那如果主线程操作 dom,然后在 Web worker 创建的辅助线程中也去操作 dom 呢?最终结果听谁的啊???回答:Web work 创建的线程中没有 document 全局文档对象,所以无法操作 dom,另外,也不会这样做的
- 大家这样理解:在实际开发场景中
Web Worker
主要,多数,应用在前端一些复杂中运算 - 而大家都知道一些复杂的运算,基本上交由后端去处理(实际上复杂的运算操作,后端也会看情况去开启多线程操作的)
- 这样说来,
Web Worker
的作用就是把后端进行的多线程操作运算拿到前端了
- 工作中一些数据的加工、计算、组装逻辑操作,常常是由后端来干;但是在某些情况下,如果前端去做的话,效率或许更高一些
所以 Web Worker
这个新技术的价值是什么呢?
# Web worker 创建辅助线程、帮助前端主线程进行复杂耗时的计算
一个人手不够用,那就多摇几个人。
Web worker 创建的一些辅助线程,分别去帮主线程分担一些复杂的、耗时的 js 运算,这样的话,主线程后续的代码执行就不会阻塞,当辅助线程计算出复杂耗时运算结果后,再与主线程通信,将计算出的结果告知主线程。
Web Worker`新技术价值,简而言之:`**提升前端代码运算执行效率** |
关于 Web worker
的原生语法,诸如:
// 创建一个 Web worker | |
var myWorker = new Worker('worker.js'); | |
// 使用 Web worker 发送消息 | |
worker.postMessage(params) | |
// 使用 Web worker 接收消息 | |
worker.onmessage = function(e) { | |
console.log(e.data) | |
} | |
// 等等... |
Web worker
的原生语法,笔者不赘述了,大家可自行去 MDN
上的 Web Worker 去查看,
为什么不说呢?因为我们工作中开发代码,基本上都是使用框架,在框架中直接写原生的 Web worker
有许多的边界异常或者其他的情况需要控制。以 vue
框架为例,我们不能直接写 Web Worker
,需要使用 Webpack
中的 worker-loader
插件去解析 Web worker
,并且在 vue.config.js
中去做相应配置。
嗯,有些麻烦。
在这个情况下,基于 Web Worker
进行封装的插件库 vue-worker
,就闪亮登场了。
简单、好用、便于理解
这里不提 Web worker 的原生基本语法不是说大家不用看了,看还是要看的,只不过篇幅原因(懒),这里就不赘述了。
# Web Worker 的应用场景
如果大家只是写增删改查的业务代码,Web Worker 用的的确非常少
工作中那些需要进行复杂耗时的计算的逻辑代码,都可以由前端使用
Web Worker
进行计算。但是复杂耗时的计算基本上都是交由后端进行。这个普遍认知下导致其使用的比较少。
大概有以下场景:
- 加密解密数据(加密解密笔者之前接触的是
NodeRSA、md5、crypto
) - 提前获取数据,比如提前发送
ajax
请求获取接口的一些图片、数值等相关数据 - 将耗时运算交由
Web Work
处理(笔者之前做的就是这个)
不过使用的是
vue-worker
插件(基于Web Worker
封装的插件)
# vue-worker(基于 Web worker 封装的一款不错的插件)
当我们找到一款还不错的插件的时候,我们首先去 npm
官网上看看这个插件的下载量如何,以及 GitHub
的 star
数量多少。
npm
地址:https://www.npmjs.com/package/vue-worker?activeTab=versions
vue-worker
下载量截图:
好少啊,一共也才不到 3000次
下载量,这里的下载量少是因为,应用场景不多,所以大家使用的也是少,接下来谈谈自己曾经使用 Web worker
的这个场景
# 曾经应用场景
笔者之前做一个项目,页面上有很多的输入框,里面的输入框中需要填写硬件采集的:压力、温度、比热容、质量大小等很多参数,当点击计算按钮时,会把这些参数进行计算,得出的结果,以供工作人员进行工作参考。
相当于一个 计算器
,只不过 计算时间会很长
本来说是把这个计算过程交给后端计算,只不过当时后端的同事有事情,请假一周。但是工作不能停下啊
于是笔者就想能不能前端计算呢?
经过一系列调研(谷歌一下),找到了 vue-worker
插件
最终是由笔者这个前端去做的这个计算,时间挺好,产品喜笑颜开
# 使用步骤
1. 下载依赖包
cnpm i vue-worker --save |
2. 在入口文件中引入
import Vue from 'vue' | |
import VueWorker from 'vue-worker' // Web worker 插件 | |
Vue.use(VueWorker) |
3. 使用
接下来,笔者举两个例子,更加便于大家理解
# 案例一 主线程渲染 dom、辅助线程进行计算
需求:
- 点击按钮进行计算,计算执行两个
UI操作
- 第一个
UI操作
,计算斐波那契数fib(44)
的值,且统计计算所用的时长,并写入到页面上 - 第二个
UI操作
,每隔0.1秒
,更新页面上h2标签
的内容值 - 要求两个操作
不阻塞
,不能出现后一个UI操作
要等待前一个UI操作
的情况 - 因为
斐波那契是递归执行
,是一个比较耗时的操作fib(44)
- 那就想办法不让这个耗时的操作堵塞住任务队列
我们使用 vue-worker
提供的方法: this.$worker.run(func, [args]?)
写法如下:
html | |
<h1>开启一个线程运算用$worker.run方法</h1> | |
<br /> | |
<el-button | |
@click="openOneThread" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 16px" | |
>计算斐波那契数列值和用时,以及渲染页面两个任务</el-button | |
> | |
<div> | |
斐波那契值为:<span class="bold"></span> | |
<i v-show="btnLoading" class="el-icon-loading"></i> | |
执行用时: | |
<i v-show="btnLoading" class="el-icon-loading"></i> | |
<span class="bold"></span> | |
毫秒 | |
</div> | |
js | |
// data | |
worker: null, | |
btnLoading: false, | |
fibNum: 44, | |
fibRes: null, // 斐波那契计算的结果 | |
fibTime: null, // 斐波那契计算用时 | |
// methods | |
openOneThread() { | |
/* 第一个UI操作 */ | |
this.btnLoading = true; | |
this.worker = this.$worker // this.$worker.run(func, [args]?) 一次性的,自动销毁 | |
.run( | |
(n) => { | |
// 注意这里的函数是内部另一个线程空间的,不能从外部引入过来(内存空间隔离) | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
let start = Date.now(); // console.time()和console.timeEnd()直接拿不到值,就换种方式 | |
let res = fib(n); | |
let end = Date.now(); // window.performance.now()也不能用,因为没window对象 | |
return [res, end - start]; // 返回数组,第一项是fib(44)的值,第二项是fib(44)递归计算用时 | |
}, | |
[this.fibNum] // 参数,从这里传递进去,数组形式 | |
) | |
.then((res) => { | |
console.log("then", res); // 另一个线程执行完以后就能拿到结果了 | |
this.fibRes = res[0]; | |
this.fibTime = res[1]; | |
this.btnLoading = false; | |
}) | |
.catch((err) => { | |
console.log("err", err); | |
this.btnLoading = false; | |
}); | |
/* 第二个UI操作 */ | |
let h2Dom = this.$refs.renderH2; | |
let n = 0; | |
let timer = setInterval(() => { | |
if (n >= 60) { | |
clearInterval(timer); | |
} else { | |
n++; | |
h2Dom.innerHTML = n; | |
} | |
}, 100); | |
// 使用web worker插件vue-work的确可以做到不阻塞 | |
}, | |
效果图 |
# 案例二 开启三个辅助线程进行计算看时间
案例一,已经可以看到 Web Worker
的 优势
了。接下来,我们再举个例子。
需求:需要计算 3个fib(30)
,如果我们使用 Promise
,写法是这样的:
# Promise.all 进行计算
async usePromiseFn() { | |
function asyncOne() { | |
let async1 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async1; | |
} | |
function asyncTwo() { | |
let async2 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async2; | |
} | |
function asyncThree() { | |
let async3 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async3; | |
} | |
console.time("使用Promise搭配aysnc和await"); | |
//let paramsArr = [asyncOne ()]; // 计算一个大概在 3 秒左右(计算一次刷新一次页面,精确一些) | |
let paramsArr = [asyncOne(), asyncTwo(), asyncThree()]; // 计算三个耗时任务大概在 9 秒左右 | |
let res = await Promise.all(paramsArr); | |
console.timeEnd("使用Promise搭配aysnc和await"); | |
console.log("结果", res); | |
}, | |
}, |
使用 Promise.all
方法去计算 3个fib值
,用时在 9秒左右
,的确是有些慢。那么,我们使用 Web Worker
方式呢?
此外,使用 Promise.all
控制台也会有警告提醒: [Violation] 'click' handler took 8822ms
意思是:
click
事件中执行的程序耗时过长
,看到没,如果使用js
的主线程
去进行复杂计算,浏览器都看不下去了...
再一个,大家在 Promise执行
的时候,去选中页面上的文字,发现选中不了! 就像卡住了一样!
从这个方面也说明, js主线程
不适合执行复杂的运算, 阻塞...
# Web Worker 进行计算
这里使用 this.$worker.create
方法,搭配 this.worker2.postAll
方法
代码写法如下
created() { | |
// 1. 定义线程所用的消息函数数组 | |
const actions = [ | |
{ | |
message: "fn1", //message 消息与 func 函数执行为映射关系 | |
func: (params1, params2) => { | |
console.log("params参数-->", params1, params2); | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
return fib(30); | |
}, | |
}, | |
{ | |
message: "fn2", | |
func: () => { | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
return fib(30); | |
}, | |
}, | |
{ | |
message: "fn3", | |
func: () => { | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
//throw "一个报错挂了,其他的也跟着挂了,走.catch"; // 抛出错误 (的确很像 Promise.all ()) | |
return fib(30); | |
}, | |
}, | |
]; | |
// 2. 根据消息函数数组去 create 创建一个 worker,并存到 data 变量中去,以便于后续随时使用 | |
this.worker2 = this.$worker.create(actions); | |
}, | |
// 点击触发 noParamsFn 方法执行 | |
// 使用多个线程 | |
noParamsFn() { | |
this.loadingOne = true; | |
console.time("多个线程计算用时1"); | |
this.worker2 | |
.postAll() | |
.then((res) => { | |
console.timeEnd("多个线程计算用时1"); | |
console.log("res", res); // 结果是一个数组 [267914296, 433494437, 701408733] | |
this.loadingOne = false; | |
}) | |
.catch((err) => { | |
console.timeEnd("多个线程计算用时1"); | |
console.log("err", err); | |
this.loadingOne = false; | |
}); | |
}, |
我们看一下效果图
看到没有。只用了 53毫秒
!
- 使用主线程去计算
3个fib(30)
的值,需要将近9秒
的时间 - 而使用
Web Worker
去创建三个辅助线程分别去运算fib(30)
所需要的时间,只需要50多毫秒
性能提升了 100 多倍!
这个案例才真正的体现了, Web Worker
开启多线程运算提高效率的强大!
大家可以去笔者的个人网站上去看完整的效果图:http://ashuai.work:8888/#/myWork
Web Worker
是HTML5
提出的规范
,主流浏览器都已经得到了兼容。IE
就忽略吧
# 附上案例完整代码
篇幅有限,一些 vue-worker
插件常用的使用语法细节,写在代码中了,大家复制粘贴即可使用
<template> | |
<div class="threadWrap"> | |
<h1>开启一个线程运算用$worker.run方法</h1> | |
<br /> | |
<el-button | |
@click="openOneThread" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 16px" | |
>计算斐波那契数列值和用时,以及渲染页面两个任务</el-button | |
> | |
<div> | |
斐波那契值为:<span class="bold"></span> | |
<i v-show="btnLoading" class="el-icon-loading"></i> | |
执行用时: | |
<i v-show="btnLoading" class="el-icon-loading"></i> | |
<span class="bold"></span> | |
毫秒 | |
</div> | |
<br /> | |
<div class="UI"> | |
<span>不阻塞后续的代码执行:</span> | |
<h2 ref="renderH2"></h2> | |
</div> | |
<br /> | |
<br /> | |
<h1>开启多个线程使用$worker.create、postAll方法</h1> | |
<br /> | |
<el-button | |
@click="noParamsFn" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 12px" | |
:loading="loadingOne" | |
>不传参都执行一次</el-button | |
> | |
<el-button | |
@click="byMessageNameStrFn" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 12px" | |
:loading="loadingTwo" | |
>根据message的名字指定谁执行(字符串形式)</el-button | |
> | |
<el-button | |
@click="byMessageNameObjParamsFn" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 12px" | |
:loading="loadingThree" | |
>根据message的名字指定谁执行(对象形式可传参)</el-button | |
> | |
<div class="info">F12请打开控制台查看--></div> | |
<br /> | |
<h1>不使用多线程,使用Promise.all太耗时啦!</h1> | |
<br /> | |
<el-button | |
@click="usePromiseFn" | |
type="success" | |
plain | |
size="small" | |
style="margin-bottom: 12px" | |
>Promise执行多个任务</el-button | |
> | |
<div class="info">F12请打开控制台查看--></div> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: "myWorkName", | |
data() { | |
return { | |
worker: null, | |
btnLoading: false, | |
fibNum: 44, | |
fibRes: null, | |
fibTime: null, | |
/****/ | |
loadingOne: false, | |
loadingTwo: false, | |
loadingThree: false, | |
worker2: null, | |
}; | |
}, | |
methods: { | |
/** | |
* 需求:点击数据计算进行两个操作 | |
* 第一个 UI 操作,计算斐波那契数 fib (44) 的值,且统计计算所用的时长,并写入到页面上 | |
* 第二个 UI 操作,每隔 0.1 秒,更新页面上 h2 标签的内容值 | |
* 要求两个操作不阻塞,不能出现后一个 UI 操作要等待前一个 UI 操作的情况 | |
* 因为斐波那契是递归执行,是一个比较耗时的操作 fib (44) 约需要近 8 秒的计算时间 | |
* */ | |
openOneThread() { | |
/* 第一个 UI 操作 */ | |
this.btnLoading = true; | |
this.worker = this.$worker //this.$worker.run (func, [args]?) 一次性的,自动销毁 | |
.run( | |
(n) => { | |
// 注意这里的函数是内部另一个线程空间的,不能从外部引入过来(内存空间隔离) | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
let start = Date.now(); //console.time () 和 console.timeEnd () 直接拿不到值,就换种方式 | |
let res = fib(n); | |
let end = Date.now(); //window.performance.now () 也不能用,因为没 window 对象 | |
return [res, end - start]; // 返回数组,第一项是 fib (44) 的值,第二项是 fib (44) 递归计算用时 | |
}, | |
[this.fibNum] // 参数,从这里传递进去,数组形式 | |
) | |
.then((res) => { | |
console.log("then", res); // 另一个线程执行完以后就能拿到结果了 | |
this.fibRes = res[0]; | |
this.fibTime = res[1]; | |
this.btnLoading = false; | |
}) | |
.catch((err) => { | |
console.log("err", err); | |
this.btnLoading = false; | |
}); | |
/* 第二个 UI 操作 */ | |
let h2Dom = this.$refs.renderH2; | |
let n = 0; | |
let timer = setInterval(() => { | |
if (n >= 60) { | |
clearInterval(timer); | |
} else { | |
n++; | |
h2Dom.innerHTML = n; | |
} | |
}, 100); | |
// 使用 web worker 插件 vue-work 的确可以做到不阻塞 | |
}, | |
/** | |
* 使用多个线程 | |
* */ | |
// 调用方式一 不传参 | |
noParamsFn() { | |
this.loadingOne = true; | |
console.time("多个线程计算用时1"); | |
this.worker2 | |
.postAll() | |
.then((res) => { | |
console.timeEnd("多个线程计算用时1"); | |
console.log("res", res); // 结果是一个数组 [267914296, 433494437, 701408733] | |
this.loadingOne = false; | |
}) | |
.catch((err) => { | |
console.timeEnd("多个线程计算用时1"); | |
console.log("err", err); | |
this.loadingOne = false; | |
}); | |
}, | |
// 调用方式二 根据 message 的名字去指定谁(可多个)去执行 字符串形式 | |
byMessageNameStrFn() { | |
this.loadingTwo = true; | |
console.time("多个线程计算用时2"); | |
this.worker2 | |
.postAll(["fn1", "fn3"]) // 这里指定 "fn1", "fn3" 去执行 | |
.then((res) => { | |
console.timeEnd("多个线程计算用时2"); | |
console.log("res", res); // 结果是一个数组 [267914296, 701408733] | |
this.loadingTwo = false; | |
}) | |
.catch((err) => { | |
console.timeEnd("多个线程计算用时2"); | |
console.log("err", err); | |
this.loadingTwo = false; | |
}); | |
}, | |
// 调用方式三 根据 message 的名字去指定谁(可多个)去执行 对象形式 | |
byMessageNameObjParamsFn() { | |
this.loadingThree = true; | |
console.time("多个线程计算用时3"); | |
this.worker2 | |
.postAll([{ message: "fn1", args: ["代码修仙路漫漫", "加油干"] }]) // 这里指定 "fn1" 去执行 | |
.then((res) => { | |
console.timeEnd("多个线程计算用时3"); | |
console.log("res", res); // 结果是一个数组 [] | |
this.loadingThree = false; | |
}) | |
.catch((err) => { | |
console.timeEnd("多个线程计算用时3"); | |
console.log("err", err); | |
this.loadingThree = false; | |
}); | |
}, | |
/** | |
* 使用 Promise | |
* */ | |
async usePromiseFn() { | |
function asyncOne() { | |
let async1 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async1; | |
} | |
function asyncTwo() { | |
let async2 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async2; | |
} | |
function asyncThree() { | |
let async3 = new Promise(async (resolve, reject) => { | |
function fib(n) { | |
if ((n === 1) | (n === 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 1); | |
} | |
} | |
resolve(fib(30)); | |
}); | |
return async3; | |
} | |
console.time("使用Promise搭配aysnc和await"); | |
//let paramsArr = [asyncOne ()]; // 计算一个大概在 3 秒左右(计算一次刷新一次页面,精确一些) | |
let paramsArr = [asyncOne(), asyncTwo(), asyncThree()]; // 计算三个耗时任务大概在 9 秒左右 | |
let res = await Promise.all(paramsArr); | |
console.timeEnd("使用Promise搭配aysnc和await"); | |
console.log("结果", res); | |
}, | |
}, | |
created() { | |
// 1. 定义线程所用的消息函数数组 | |
const actions = [ | |
{ | |
message: "fn1", //message 消息与 func 函数执行为映射关系 | |
func: (params1, params2) => { | |
console.log("params参数-->", params1, params2); | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
return fib(30); | |
}, | |
}, | |
{ | |
message: "fn2", | |
func: () => { | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
return fib(30); | |
}, | |
}, | |
{ | |
message: "fn3", | |
func: () => { | |
function fib(n) { | |
if ((n == 1) | (n == 2)) { | |
return 1; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
//throw "一个报错挂了,其他的也跟着挂了,走.catch"; // 抛出错误 (的确很像 Promise.all ()) | |
return fib(30); | |
}, | |
}, | |
]; | |
// 2. 根据消息函数数组去 create 创建一个 worker,并存到 data 变量中去,以便于后续随时使用 | |
this.worker2 = this.$worker.create(actions); | |
}, | |
// 别忘了在组件销毁前清除掉哦 | |
beforeDestroy() { | |
this.worker = null; | |
}, | |
}; | |
</script> | |
<style lang='less' scoped> | |
.bold { | |
font-weight: 700; | |
font-size: 24px; | |
} | |
.info { | |
color: #999; | |
font-size: 13px; | |
} | |
.UI { | |
display: flex; | |
align-items: center; | |
} | |
</style> |
或者大家去笔者的 GitHub仓库
中拉取代码,跑起来看,更加方便理解。
GitHub仓库
地址:https://github.com/shuirongshuifu/elementSrcCodeStudy
# js 中统计代码执行时长的三种方式
附带 js
中常用的 统计程序执行时长
的三种方式
- window.performance.now()
- https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now
// 计算时间方式一 | |
function fib(n) { | |
if (n === 1 | n === 2) { | |
return 1 | |
} else { | |
return fib(n - 1) + fib(n - 2) | |
} | |
} | |
let start = window.performance.now() // 单位毫秒 | |
fib(40) | |
let end = window.performance.now() // 单位毫秒 | |
console.log((end - start).toFixed(0) + '毫秒'); |
// 计算时间方式二 | |
function fib(n) { | |
if (n === 1 | n === 2) { | |
return 1 | |
} else { | |
return fib(n - 1) + fib(n - 2) | |
} | |
} | |
let start = Date.now() // 单位毫秒 | |
fib(40) | |
let end = Date.now() // 单位毫秒 | |
console.log((end - start).toFixed(0) + '毫秒'); |
- console.time() & console.timeEnd()
- https://developer.mozilla.org/zh-CN/docs/Web/API/Console/time
console.time('tom') | |
console.timeEnd('tom') | |
A good memory is not as good as a bad pen, record it... |
转自原文作者:水冗水孚原文链接