概述
js采用的是单线程模型,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着,而遇到异步耗时操作的逻辑的时候,一般会使用到JavaScript的异步机制,通过事件循环加回调函数的方式来处理耗时操作,但是遇到类似Json.parse()这种同步代码操作的时候,就同样会阻塞后续代码的执行,假设后端返回了一个特别大的json数据,我们前端获取到数据的时候,一般会json.parse进行序列化,但是大数据意味着执行相关转化逻辑的时候就会阻塞代码的执行,那么这样的耗时操作我们就可以使用到webwork了。
web work的理解
我的理解其实是:webwork就是为js创造多线程的环境,允许主线程创建webwork线程,将未处理的一些任务分给后者 运行.在js主线程运行的同时,work线程在后台运行,两者互不打扰,等到webwork线程的任务结束后,通过发布订阅的模式将消息发布给订阅者。
使用方法
编写computed.js 该线程执行一段计算,耗时特别长。
//webwork线程
let count = 0;
for (let i = 0; i < 10000000000; i++) {
count += i;
}
//这里线程不能访问window对象,只有仅有的部分api放到,不能操作dom,线程之间通过postMessage传递信息
postMessage({
count
});
编写index.html 我们将很大计算量的工作使用webwok开启的线程进行处理,然后计算完成后通知主线程进行另外的路径处理。避免主线程代码执行阻塞。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
let work = new Worker("./computed.js");
work.onmessage = (e) => {
//大概一分钟后计算出结果,这里取到结果
console.log(e)
}
console.log("主线程")
</script>
</html>
webwork如何订阅主线程发过来的消息呢 更改computed.js
self.onmessage = (e) => {
console.log("work message", e);
};
更改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text">
</body>
<script>
let work = new Worker("./computed.js");
let input = document.querySelector("input")
work.onmessage = (e) => {
console.log(e);
}
work.postMessage("hah1")
//新增
input.oninput = (e) => {
work.postMessage(e.target.value)
}
</script>
</html>
在webpack5环境下配置
从 webpack 5 开始,你可以使用 Web Workers 代替 worker-loader
语法
new Worker(new URL('./worker.js', import.meta.url));
选择这种语法是为了实现不使用 bundler 就可以运行代码,它也可以在浏览器中的原生 ECMAScript 模块中使用。
请注意,虽然 Worker API 建议 Worker 构造函数接受表示 URL 的字符串脚本,在 webpack 5 中你只能使用 URL 代替。
示例
src/index.js
const worker = new Worker(new URL('./deep-thought.js', import.meta.url));
worker.postMessage({
question:
'The Answer to the Ultimate Question of Life, The Universe, and Everything.',
});
worker.onmessage = ({ data: { answer } }) => {
console.log(answer);
};
src/deep-thought.js
self.onmessage = ({ data: { question } }) => {
self.postMessage({
answer: 42,
});
};
vue-cli环境下使用
假设我们有个网络请求需要耗时很久,并且解析json也需要很久,这时候可以考虑使用webwork APP.vue
<template>
<div>
<h2>this is app</h2>
<div>
<h2>this is Home component</h2>
<Home></Home>
</div>
<div>
<h2>this is Home component</h2>
<About></About>
</div>
<button @click="handleAdd">增加</button>
<p>{{ count }}</p>
<p v-if="loading">loading....</p>
<p v-if="loading">数据加载完成</p>
</div>
</template>
<script>
import Home from "./pages/Home";
import About from "./pages/About";
export default {
components: { Home, About },
data() {
return {
count: 1,
loading: true
};
},
mounted() {
const worker = new Worker(new URL("./deep-thought.js", import.meta.url));
worker.postMessage({
question:
"The Answer to the Ultimate Question of Life, The Universe, and Everything."
});
worker.onmessage = (data) => {
this.count = data.data.answer;
this.loading = false;
};
},
methods: {
handleAdd() {
this.count++;
console.log(this.count);
}
}
};
</script>
deep-thought
import axios from "axios";
self.onmessage = ({ data: { question } }) => {
axios.get("http://192.168.2.119:8081").then((res) => {
let count = 0;
for (let i = 0; i < 10000000000; i++) {
count += i;
}
self.postMessage({
answer: count,
data: res.data
});
});
};