您的位置:首页 > Web前端 > HTML5

HTML5 New Feature Series: Web Workers

2016-03-08 13:11 567 查看
As we know, client-side JavaScript runs in single thread, in other words, JavaScript and UI rendering program share the main thread, that means, UI rendering will be blocked when JavaScript is working on high-loading processing, thereby user experience will
be seriously falling down. As one of HTML5 features, Web Workers create a new running mechanism to make JavaScript run an extra thread in new environment, so that we can do some time-consuming tasks. And next, let's learn the details related to Web Workers.

In short, Web Workers can create an independent work thread via loading an external script file, and then run the task out of main thread. Creating a work thread is pretty simple, just like the following code:

var worker = new Worker('js/worker.js');
As the code shows, we only need to provide the path of script file as a parameter in the constructor of the 'Worker' object, and then, a Web Worker instance will be created, and the work thread will be running behind the UI. It should be noted
that we're only able to load the script file of the same origin in our project due to the same-origin policy.

And when creating work thread has done, we can message with it in main thread, and that utilizes the 'postMessage' function to send message to work thread, in work thread, we can capture the 'message' event to receive message from main thread. In 'postMessage'
function we can pass variety of data types, but note that, some special BOM objects are excluded, such as 'document'.

Now let's see how does it work in main thread:

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

//message receiving
worker.onmessage = function(event) {
var data = event.data;
//to do
}
Similarly, in work thread we can also use 'postMessage' and 'onmessage' functions to send or receive message from main thread, below is the code in worker.js file:

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

//message receiving
self.onmessage = function(event) {
var data = event.data;
//to do
}
In certain circumstances, we have no choice but to interrupt the running work thread, in main thread we can use the 'terminate' method, and in work thread we can call 'close' method of worker instance to interrupt it self, just like the following
code shows:

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

//interrupt work thread it self
self.close();

The above shows some basic usage of Web Workers, and next let's show a real scenario in an example.

Usually we will join some technology groups to discuss the latest technologies and to get acquainted with other guys, make friends. Assume that we want to look for someone in the group, it's quite inconvenient when group is to large, therefore, we plan to
add a searching functionality to this group, make it easy to get the matched data by keywords, just like the following picture shows:



In this case, the group data has been loaded to client in advance, and the searching functionality will be achieved entirely in client, if the data is too large, this simple searching probably can cause a certain decline on user experience. Hence, we plan
to implement this manipulation by Web Workers. Now let's take a look at the basic structure of the example project:



We can easily see, there is a worker.js file in js folder, it's used to put the logic of work thread, and it will be loaded by main thread at runtime, we're going to explain it later. Now let's take a glance at the structure in main page:

<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>


Looks pretty simple, contains a search input and search button, below them is the search result display area. In order to get it to run, we also need the collaboration of main.js, below is the code:

//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);
In the code snippet, we will load the worker.js firstly, and then instantiate a Worker object, after that capture the message event, and then show the result data in corresponding area. And the search function is responsible for listening button
click event, and post a message to work thread carrying the group data and search keywords to hand over the task to work thread.

And now let's figure it out how does worker.js work:

//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;
}
In the above code, at first we captured the message event in work thread to receive the group data and keywords, and then called search function, at last sent back the results to main thread, the whole searching finished.

Above is the details of Web Worker's usage, and in real development we may face with many complicated operations in client, in this scenario we can consider Web Workers to be the best choice to complete the complex task in work thread, and then reduce UI
block in main thread, if so we will get a significant improvement on user experience.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: