前言
做了这么久的前端,在印象中一直以来认为js只是单线程的,包括一些异步的操作也只能说算是伪多线程。
现在可以很确定的告诉你,js并不是只能单线程,是可以多线程的。
它主要通过HTML5一个新的API - Worker
来实现的。
接下来我们就进一步来了解如何一步一步的实现一个简单的多线程。
正文
首先我们来看一下它的兼容性:
整体来说兼容性不错,只有IE只兼容到10略微有些差强人意。
那么我们要如何来使用它呢?
首先要通过Worker()
构造函数创建支线程对象,该函数接受一个指定URL的js文件。
即为:
Worker(
in DOMString aStringURL
);
该对象会返回一个worker对象,该对象即为支线程对象。
到这里,我们要注意:
- 要清楚主线程和支线程的概念,在当前环境中运行的js即为主线程,通过
Worker()
创建的线程即为支线程; - 主线程和支线程必须遵循同源策略;
- 支线程并不能进行DOM操作,它是浏览器中后台独立出的运行,但是还是有一些方法是可以调用的,这里我们给出一个列表:函数列表;
在创建好Worker
对象后,它主要提供有两个方法:
//用于主线程和支线程之间相互通信
void postMessage(in JSObject message);
//用于关闭支线程
void terminate();
其中postMessage()
方法在主线程和支线程环境中通用,主线程中通过创建的Worker
对象调用该方法并传入一个通信对象,便将数据传输给支线程。
同理,在支线程中也可以回传通信对象给主线程,但是在支线程环境中我们通过什么对象来调用这个方法呢?
此时,在支线程环境中,有一个默认的self
对象,可以通过它来传输通信对象,即为:
self.postMessage({ number: 1 });
至于terminate()
就是简单的关闭支线程,只能在主线程环境中使用:
worker.terminate();
我们刚刚只提到了主支线程之间互相如何发送通信对象,但是并未提到如何接收,接下来我们来看它们又是如何如想接收信息的。
该对象还提供两个事件:
//主支实时接收通信的事件,其中我们传输的通信对象保存在回调函数参数e.data对象上
Worker.onmessage = function(e) { ... };
//用于出现错误时的回调
Worker.onerror = function() { ... };
其中onmessage
事件也是主支线程都可以使用的,原理同postMessage()
方法,在主线程通过Worker
对象调用,在支线程通过self
对象调用。
它可以做到实时监听两个线程之间的postMessage()
方法,当其中一方发起传输,另一方就进入事件并接收到通信数据对象。
具体的使用我们就讲到这里,接下来我们看一个Worker
的具体使用。
我们知道在单线程的环境下,通过alert()
的方式弹窗可以阻塞线程的运行,那么接下来我们看:
在传统环境下:
var i = 0;
setInterval(function(){
i++;
if(i === 10){
alert('yep');
}
},1000);
在我们不点击弹窗关闭的情况下,计数会一直停留在10上。
在Worker
环境下:
//main.js
var worker = new Worker('worker.js');
worker.onmessage = function(e){
if(e.data === 10){
alert('yep');
}
};
//worker.js
var i = 0;
setInterval(function(){
i++;
self.postMessage(i);
},1000);
在当前环境下,我们仍旧不点击弹窗关闭,计数并不会停止,而是继续计数,并未受到主线程的阻塞影响。
最后
关于多线程的内容就告一段落了。
至于它的用途,可以使用在复杂的运算、在考虑到线程阻塞的情况下可以使用。
我们将在下一篇文章中来具体使用它到实际当中。