HTML5新特性之Web Workers

我们知道浏览器端JavaScript是以单线程的方式执行的,也就是说JavaScript和UI渲染占用同一个主线程,那就意味着,如果JavaScript进行高负载的数据处理,UI渲染就很有可能被阻断,从而造成用户体验的大打折扣。Web Workers作为HTML5新特性之一,为浏览器端JavaScript开创了一种新的运行模式,使之能够在另外的线程中创建新的运行环境,以便使JavaScript能够在后台做一些费时的处理。下面我们就来详细介绍一下Web Workers方面的知识。

Web Workers可以通过加载一个脚本文件,进而创建一个独立的工作线程,在主线程之外运行。工作线程的创建比较简单,代码如下:

var worker = new Worker('js/worker.js');
如代码所示,我们只需将含有工作线程的代码文件路径作为参数传入到Worker构造函数中,即可创建一个工作线程,使其能够在后台执行。需要注意的是,脚本的加载有同源策略的限制,所以必须指定与主线程同源的文件。

在创建完工作线程后,我们就可以在主线程中与工作线程通信了。主线程中通过postMessage方法向工作线程发送消息,也可以通过捕获worker实例的message事件来接收来自工作线程的消息。需要注意的是,在postMessage方法中,我们可以相对自由的传递各种类型的数据,但是像document等BOM对象是无法被传递的。下面就让我们来看看主线程中是如何和工作线程交互的:

//message sending
worker.postMessage({name: 'Scott'});

//message receiving
worker.onmessage = function(event) {
	var data = event.data;
	//to do
}
同样的,在工作线程中我们也可以通过postMessage和onmessage方法来发送和接收数据,下面是工作线程文件worker.js中的代码:

//message sending
self.postMessage({name: 'Worker'});

//message receiving
self.onmessage = function(event) {
	var data = event.data;
	//to do
}

在某些情况下,我们不得不中断工作线程的运行,主线程中我们可以调用worker实例的terminate方法,在工作线程中我们也可以调用close方法中断自身,代码如下:

//interrupt a work thread in main thread
worker.terminate();

//interrupt work thread it self
self.close();
以上介绍了Web Workers的基本用法,接下来我们来以一个实例说明它在实际项目中是如何应用的。

我们经常会加入一些技术群组里探讨技术,广交朋友,如果群组成员太多,查看起来就不太方便,为此我们打算给这个群组加一个搜索的功能,根据关键字搜索与成员信息匹配的数据,就像下面图中所示:


在这个案例中,群组成员信息预先加载到了客户端,搜索功能也是在客户端完成的,假如数据非常多,一个简单的搜索可能就会在用户体验上造成不小的折扣,我们打算用Web Workers来实现这个操作。现在来看一下示例项目的基本目录结构:


我们可以看到,在js目录中有个worker.js文件,用于放置工作线程的逻辑代码,此文件在运行时被主线程加载,我们稍后会详细讲解。现在我们先看一下主页面的基本结构:

<html>
	<head>
		<title>Web Worker</title>
		<link rel="stylesheet" type="text/css" href="css/main.css">
	</head>
	<body>
		<div id="searching">
			<input id="keywords" type="text" placeholder="type in to start searching">
			<button id="search-button" οnclick="search();">search</button>
			<div id="members">
				<!-- <div class="member">
					<img src="img/icon.png">
					<div class="info">
						<p>John Li</p>
						<p>Java programming, Python language</p>
					</div>
					<a class="add">+Add</a>
				</div> -->
				<!-- the search results will be here -->
			</div>
		</div>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript" src="js/main.js"></script>
	</body>
</html>
看起来很简单,一个搜索框和搜索按钮,下面是搜索结果显示区域。为了使其运行起来,我们还需要main.js的配合,代码如下:

//a simple group member data example
var groupMembers = [
	{
		id: 101,
		name: 'John Li',
		skills: 'Java programming, Python language, MySQL'
	},
	{
		id: 102,
		name: 'Lisa Wang',
		skills: 'HTML, JavaScript, CSS, Node.js'
	},
	{
		id: 103,
		name: 'Tom Wang',
		skills: 'JavaScript, CSS, HTML5'
	},
	{
		id: 104,
		name: 'Andy Zhang',
		skills: 'PHP language, JavaScript programming, CSS'
	}
	/*
		a large number of data
	*/
];

//loading the worker.js to instantiate a Worker object
var worker = new Worker('js/worker.js');

//receive message from work thread, and then render the result data
worker.onmessage = function(e) {
	renderGroupMembers(e.data.results);
};

function search() {
	var keywords = $('#keywords').val().trim();
	
	//post a message to work thread
	worker.postMessage({
		groupMembers: groupMembers,
		keywords: keywords
	});
}

function renderGroupMembers(members) {
	var html = '';
	members.forEach(function(member) {
		var resultHtml = '<div class="member">'
			 		   + '	<img class="icon" src="img/icon.png">'
			 		   + '	<div class="info">'
			 		   + '		<p>' + member.name + '</p>'
			 		   + '		<p>' + member.skills + '</p>'
			 		   + '	</div>'
			 		   + '	<a class="add">+Add</a>'
			 		   + '</div>';
		html += resultHtml;
	});

	$('#members').html(html);
}

renderGroupMembers(groupMembers);
在这段代码中,我们首先会加载worker.js,实例化一个Worker对象,然后捕获message事件,进而将搜索结果显示到相应区域。而search函数负责监听搜索按钮的点击事件,然后向工作线程发送带有群组数据和关键字的消息,将搜索任务交给工作线程。

最后,我们开看看worker.js是如何运行的:

//receive the message from main thread
self.onmessage = function(e) {

	var groupMembers = e.data.groupMembers;
	var keywords = e.data.keywords;

	var results = searchByKeywords(groupMembers, keywords);

	//post the result message to main thread
	self.postMessage({results: results});
};

//it may be quite complicated in real application
function searchByKeywords(groupMembers, keywords) {
	var results = [];

	keywords = keywords.toLowerCase();

	groupMembers.forEach(function(member) {
		var nameMatched = member.name.toLowerCase().indexOf(keywords) > -1;
		var skillsMatched = member.skills.toLowerCase().indexOf(keywords) > -1;
		
		if (nameMatched || skillsMatched) {
			results.push(member);
		}
	});

	return results;
}
从上面的代码中可以看到,首先我们会捕获工作线程的message事件,接收群组数据和关键字,然后调用搜索函数,最后将搜索结果发送回主线程,完成这次的搜索任务。

以上就是Web Workers的介绍,在实际开发中,可能面临很多复杂的操作需要在前端完成,我们都可以考虑用Web Workers实现,将复杂操作交给工作线程,进而减少主线程的阻塞,在用户体验上一定会有显著的提升。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值