html5 WebWorkers 防止浏览器假死

本文解析了浏览器在处理JavaScript时可能出现的假死现象原因,并介绍了如何利用HTML5的WebWorkers特性来避免UI线程被阻塞,提升用户体验。

======================================================
注:本文源代码点此下载
======================================================

在web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出“脚本运行时间过长“的提示框,如果出现这种情况说明你的脚本已经失控了。

一个浏览器至少存在三个线程:js引擎线程(处理js)、gui渲染线程(渲染页面)、浏览器事件触发线程(控制交互)。

1:javascript引擎是基于事件驱动单线程执行的,js引擎一直等待着任务队列中任务的到来然后加以处理,浏览器无论再什么时候都只有一个js线程在运行js程序。

2:gui 渲染线程负责渲染浏览器界面,当界面需要重绘(repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 gui渲染线程与js引擎是互斥的,当js引擎执行时gui线程会被挂起,gui更新会被保存在一个队列中等到js引擎空闲时立即被执行。

3:事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待js引擎的处理。这些事件可来自javascript引擎当前执行的代码块如settimeout、也可来自浏览器内核的其他线程如鼠标点击、ajax异步请求等,但由于js的单线程关系所有这些事件都得排队等待js引擎处理。

了解了浏览器的内核处理方式就不难理解浏览器为什么会进入假死状态了,当一段js脚本长时间占用着处理机就会挂起浏览器的gui更新,而后面的事件响应也被排在队列中得不到处理,从而造成了浏览器被锁定进入假死状态。另外js脚本中进行了dom操作,一旦js调用结束就会马上进行一次gui渲染,然后才开始执行下一个任务,所以js中大量的dom操作也会导致事件响应缓慢甚至真正卡死浏览器,如在ie6下一次插入大量的html。而如果真的弹出了“脚本运行时间过长“的提示框则说明你的js脚本肯定有死循环或者进行过深的递归操作了。

现在如果遇到了这种情况,我们可以做的不仅仅是优化代码,html5的webworkers提供了js的后台处理线程的api,它允许将复杂耗时的单纯js逻辑处理放在浏览器后台线程中进行处理,让js线程不阻塞ui线程的渲染。这个线程不能和页面进行交互,如获取元素、alert等。多个线程间也是可以通过相同的方法进行数据传递。

直接看代码:

例子:用户输入一个数字,进行加法运算(+=)

以前的做法:

doctype html>

html lang="en">

head>

meta charset="utf-8">

title>webworkers--calculatetitle>

head>

body>

input id="num" name="num" type="text"/>

button onclick = "calculate()">计算button>br />

div id="result" style="color:red;">div>

div id="time" style="color:red;">div>

script type="text/javascript" src="calculate.js">script>

script type="text/javascript">

function calculate(){

data1 = new date().gettime();

var num = document.getelementbyid("num").value;

var val = parseint(num,10);

var result =0;

for(var i =0; inum;i++){

result += i;

}

data2 = new date().gettime();

document.getelementbyid("result").innerhtml ="计算结果:"+result;

document.getelementbyid("time").innerhtml ="普通 耗时:"+ (data2 - data1)+"ms";

}

script>

body>

html>

使用webworkers以后:

calculate.html

doctype html>

html lang="en">

head>

meta charset="utf-8">

title>webworkers--calculatetitle>

head>

body>

input id="num" name="num" type="text"/>

button onclick = "calculate()">计算button>br />

div id="result" style="color:red;">div>

div id="time" style="color:red;">div>

script type="text/javascript" src="calculate.js">script>

script type="text/javascript">

var worker = new worker("calculate.js");

var data1 =0;

var data2 =0;

worker.onmessage = function(event){

var data = event.data;

data2 = new date().gettime();

document.getelementbyid("result").innerhtml ="计算结果:"+data;

document.getelementbyid("time").innerhtml ="workers 耗时:"+ (data2 - data1)+"ms";

};

function calculate(){

data1 = new date().gettime();

var num = document.getelementbyid("num").value;

var val = parseint(num,10);

worker.postmessage(val);

}

script>

body>

html>

calculate.js

onmessage = function(event){

var num = event.data;

var result = 0;

for(var i = 0; i

webworker需要将代码放入web服务器中,如果使用的是localhost请用高版本的chrome浏览器打开,firefox浏览器在处理localhost的时候会出现“could not get domain!”的错误,关于这个可以参考:https://bugzilla.mozilla.org/show_bug.cgi?id=682450

对比上面的两种实现方式,当计算值达到100亿的时候,普通做法耗时已经很长,且一般会卡死了。

webworkers在chrome15下的效果。 更正:gettime()返回的应该是毫秒(ms),而不是秒(s)。

普通方法在chrome15下的效果

可见webworkers在未来的web应用中还是非常有价值的。

参考资料:http://fed.renren.com/2010/01/247#more-247


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值