使用HTML5开发的应用越来越多,很多针对性能提升的新标准也开始逐渐提出,提交到HTML5、EcmaScript等标准中,给HTML5的应用更强大的计算能力。我们分4篇文章分别介绍一下这些针对HTML5性能的新标准:Web Workers, Typed Array, ParallelArray 和 asm.js。
之一:Web Workers
Web Workers是一个在前端实现多线程的JS接口,属于W3C的HTML5标准的一部分,现在大多数浏览器包括移动浏览器都支持Web Workers.
大家知道,JavaScript是一个单线程的语言,所有函数的执行实际上都是串行的。如果一个函数运行的时间过长,则会导致UI停止响应。而Web Workers可以创建一个独立的JS线程,在这个线程中的函数不会阻塞主线程(也称UI线程)的执行。如果在你的代码中有一些执行时间特别长的函数,主要是用来做复杂的数学计算而不是修改UI,就建议把函数放在Web Workers线程内执行。Web Workers也正是为这种场景来设计的,因为Web Worker拥有一个跟UI线程完全独立的环境,两者之间不共享任何内存变量,Web Worker中不包含DOM树和CSS相关的API,主线程和Worker线程之间靠消息传递来实现变量的共享。
我们来看一个例子来简单了解一下Web Worker:
页面(main.html)
<div id="result"></div>
<div>
<span>No Web Workers: </span><button onclick="uiFib(10)">uiFib(10)</button><button onclick="uiFib(40)">uiFib(40)</button>
</div>
<div>
<span>Web Workers: </span><button onclick="workerFib(10)">workerFib(10)</button><button onclick="workerFib(40)">workerFib(40)</button>
</div>
<script src="main.js"></script>
主线程文件(main.js)
// Web Worker版本的函数调用 function workerFib(n) { var worker = new Worker('worker-thread.js'); // 使用独立的文件'worker-thread.js'创建Web Worker线程 worker.onmessage = function (evt) { // 收到Worker发过来的消息 document.getElementById('result').innerHTML = evt.data; }; worker.postMessage(n); // 发送消息给Worker线程 } // 在UI线程内的函数调用 function uiFib(n) { var ret = fib(n); document.getElementById('result').innerHTML = ret; } // 递归实现的斐波那契数列计算函数 function fib (n) { if (n < 0) return -1; else if (n === 0 || n === 1) { return 1; } else { return fib(n - 2) + fib(n - 1); } }
Worker线程文件(worker-thread.js)
// 监听UI线程发过来的消息 onmessage = function (evt) { var n = evt.data; // 获取数据作为参数 var ret = fib (n); // 计算 postMessage(ret); // 将计算结果传递给UI线程 }; // 递归实现的斐波那契数列计算函数 function fib (n) { if (n < 0) return -1; // 非法参数返回-1 else if (n === 0 || n === 1) { return 1; } else { return fib(n - 2) + fib(n - 1); } }
通过浏览器打开main.html(由于安全限制需要通过HTTP服务器访问),点击uiFib(40)的按钮后你会发现UI线程被阻塞,导致整个界面在计算完成前不响应,而点击Web Worker版本的workerFib(40),由于在不同线程内执行,UI界面不会停止响应,点击其他按钮仍然有反应。