在讲之前, 大家都知道 js 是基于单线程的, 而这个线程就是浏览器的 js 引擎.
首先来看一下大家用的浏览器都具有那些线程吧.
假如我们要执行一些耗时的操作, 比如加载一张很大的图片, 我们可能需要一个进度条来让用户进行等待, 在等待的过程中, 整个 js 线程会被阻塞, 后面的代码不能正常运行, 这可能大大的降低用户体验, 这时候我们就期望拥有一个工作线程来处理这些耗时的操作. 在传统的 html 时代是基本不可能实现的, 而现在, 我们拥有一种叫做 worker 的东西. 它是 js 里的一个类, 而我们只需要创建它的实例就可以使用它.
var worker = new Worker(js file path);
构造函数的参数填上你的 js 文件的路径, 这个 js 文件将会在浏览器新开的线程里运行, 而与原先的 js 引擎的线程并不影响.
下面看个例子.
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <title></title>
- </head>
- <body>
- <input type="text" name="ipt" id="ipt" value="" />
- <button id="start">start</button>
- <button id="stop">stop</button>
- <button id="ale">alert</button>
- <script type="text/javascript">
- var ipt = document.getElementById("ipt");
- var stop = document.getElementById("stop");
- var start = document.getElementById("start");
- var ale = document.getElementById("ale");
- var worker = new Worker("js/test22.js");
- worker.onmessage = function(){
- ipt.value = event.data;
- };
- stop.addEventListener("click",function(){
- // 用于关闭 worker 线程
- worker.terminate();
- });
- start.addEventListener("click",function(){
- // 开起 worker 线程
- worker = new Worker("js/test22.js");
- });
- ale.addEventListener("click",function(){
- alert("i'm a dialog");
- });
- </script>
- </body>
- </html>
下面是 test22.js 里的代码, 也就是存在于 worker 线程里的代码
- var i = 0;
- function mainFunc(){
- i++;
- // 把 i 发送到浏览器的 js 引擎线程里
- postMessage(i);
- }
- var id = setInterval(mainFunc,1000);
运行起来我们会发现
点击确定后, 它的数值并非 2, 而是一个比 2 更大的数
虽然 dialog 的弹出会阻塞 js 引擎线程, 但是并不影响 worker 线程的运行, 所以, 在我们点击确定后, 只是在 js 引擎线程上更新了新的内容, 而数值是一直在跑动的, 这就说明 worker 线程和原本的 js 线程互不影响.
那么既然互不影响, 两个线程之间要怎么来联系呢, 答案其实已经在代码里了, 那就是 onPostMessage 和 onmessage 这两个函数, 其中 onPostMessage(data) 的参数是你要传递的数据, 而 onmessage 是一个回调函数, 只有在接受到数据时, onmessage 会被回调, onmessage 有一个隐藏的参数, 那就是 event, 我们可以用 event.data 获取到传递过来的数据来更新主线程.
使用 worker 线程应注意的是, 所有 js 里集成的对象都在 js 线程里, 而并非 worker 线程.
例如我们在 worker 线程里写上:
var a = document.getElementById("a");
结果你会得到一条 Error, 告诉你找不到 document, 或者 document is undefined. 所以我们尽量把需要的东西都写到主线程里, 而只把耗时的操作写到 worker 线程里.
来源: http://www.qdfuns.com/article/28851/fe935b05dc7c8b46a30b9c9061aebc28.html