HTML5新特性之Web Workers

来源:互联网 发布:线切割绘图编程步骤 编辑:程序博客网 时间:2024/06/14 02:36

我们知道浏览器端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 sendingworker.postMessage({name: 'Scott'});//message receivingworker.onmessage = function(event) {var data = event.data;//to do}
同样的,在工作线程中我们也可以通过postMessage和onmessage方法来发送和接收数据,下面是工作线程文件worker.js中的代码:

//message sendingself.postMessage({name: 'Worker'});//message receivingself.onmessage = function(event) {var data = event.data;//to do}

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

//interrupt a work thread in main threadworker.terminate();//interrupt work thread it selfself.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" onclick="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 examplevar 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 objectvar worker = new Worker('js/worker.js');//receive message from work thread, and then render the result dataworker.onmessage = function(e) {renderGroupMembers(e.data.results);};function search() {var keywords = $('#keywords').val().trim();//post a message to work threadworker.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 threadself.onmessage = function(e) {var groupMembers = e.data.groupMembers;var keywords = e.data.keywords;var results = searchByKeywords(groupMembers, keywords);//post the result message to main threadself.postMessage({results: results});};//it may be quite complicated in real applicationfunction 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 0
原创粉丝点击