JavaScript之多线程
我们知道客户端JavaScript其中一个基本的特性就是单线程:比如,浏览器无法同时运行两个事件处理程序,它也无法在一个事件处理程序运行的时候触发一个计时器。随着Web应用复杂性的与日俱增,越来越复杂的计算在所难免。长时间运行的JavaScript进程会导致浏览器冻结用户界面,让人感觉屏幕“冻结”了,这就造成了用户体验问题,这时候要解决这个问题就需要用到多线程操作了(多线程简单来说就是你干着这件事的同时还能做其他事情,而这两件事之间不会发生冲突)在Web Workers标准中,定义了解决客户端JavaScript无法多线程的问题。其中定义的“Worker”是指执行代码的并行线程(或者叫后台线程)。
一、worker的使用
1、怎样新建一个线程
要创建一个线程只需要实例化一个Worker对象出来就行了,然后传入对应的参数即需要在worker中运行的js脚本的url
实例:
index.js文件
var worker = new Worker(“test.js”);
这样我们就创建好了一个并行线程。
2、如何传递数据
在web workers标准中,给我们提供了一个postMissage方法来传递数据,通过message事件来接受数据。
(1)数据从并行线程传递到js主线程
实例:
test.js文件
function test(n,m){
return n*m;
}
var res = test(2,3);
postMessage(res);
index.js文件
var worker = new Worker(“test.js”);
worker.onmessage = function(e){
console.log(e.data);//6
}
这里e.data的值即为在并行线程中传递过来的数据
(2)数据从主线程传递到js并行线程
实例:
index.js文件
var worker = new Worker("test.js");
workder.postMessage("本大爷从主线程而来!")
1
2
test.js文件
onmessage = function(e){
console.log(e.data);//本大爷从主线程而来!
}
1
2
3
这样就完成了数据的相互传递,如果传递的数据不止一个,可以通过对象形式传入多个(可以随便传递任何形式的对象数据),比如:
test.js文件
var msg = “我是并行线程中的数据”;
function test(n,m){
return n*m;
}
var res = test(2,3);
postMessage({res,msg});
index.js文件
var worker = new Worker("test.js");
worker.onmessage = function(e){
console.log(e.data);
}
在e.data中同样可以得到在test.js文件里传入过来的两个数据。
1
2
3
4
5
(3)如果worker抛出异常,并且他自己没有对其进行捕获和处理,可以通过监听的一个error事件来传递异常。
实例:
index.js文件
// 记录错误消息日志:包括Worker的文件名和行数
worker.onerror = function(e) {
console.log("Error at " + e.filename + “:” + e.lineno + ": " + e.message);
}
3、如何结束并行线程
Worker对象有一个方法:terminate(),该方法强制一个worker线程结束运行。
实例:
index.js文件
worker.terminate();
二、Worker的作用域
关于Web Worker,最重要的是要知道它所执行的JavaScript代码完全在另一个作用域中,与当前网页中的代码不共享作用域*(因此在worker代码中不能进行DOM操作)*。WorkerGlobalScope全局对象表示了该新的运行环境。WorkerGlobalScope对象在某种程度上来说是大于核心的JavaScript全局对象,但又小于整个客户端的Window对象。同样在WorkerGlobalScope中也有postMessage和message方法。
WorkerGlobalScope是一个供Worker使用的全局对象,因此该对象上的postMessage方法和onmessage属性在worker代码中使用的时候,看起来像是全局函数和全局变量。因为WorkerGlobalScope是Worker的全局对象,所以它有所有核心JavaScript全局对象拥有的那些属性,诸如JSON对象、isNaN()函数和Date()构造函数,最小化的navigator 对象,包括onLine 、appName 、appVersion 、userAgent 和platform 属性; 只读的location 对象; setTimeout() 、setInterval() 、clearTimeout() 和clearInterval() 方法;XMLHttpRequest 构造函数。
WorkerGlobalScope对象上定义了一个很有意思的全局函数,importScripts,Worker可以使用此方法来加载任何需要的库代码。
实例:
test2.js文件
var num = 88888;
test.js文件
importScripts(“test2.js”);
console.log(num);//88888
在test.js文件通过importScripts引入test2.js文件,即可访问到test2脚本里面的变量。
注意:importScripts是一个同步的方法,他直到所有的脚本都已经载入并运行完成才会返回。
目前支持web workers的浏览器有IE10+、Firefox3.5+、Safari4+、Opera 10.6+、chrome和ISO版的Safari。
小结
Web workers:可以运行异步JavaScript代码,避免阻塞用户界面,在执行复杂计算和数据处理的时候,这个API非常有用,不然,这些任务轻则会占用很长时间,重则会导致用户无法与页面交互。