HTML教程 HTML教程HTML是什么HTML 代码编辑器HTML 基础标签HTML 元素HTML 属性HTML 标题HTML 段落HTML 文本格式化HTML CSSHTML 头部HTML链接HTML 图像HTML 区块和行内元素HTML 表格HTML 列表HTML 引用和定义元素HTML 计算机代码元素HTML 布局HTML 框架HTML 脚本/JavaScriptHTML 文件路径HTML 颜色HTML 字符(编码)和实体HTML URL(网址)HTML XHTMLHTML - Web服务器HTML空格符(空格的代码)HTML表单 HTML 表单HTML 表单属性HTML 表单元素HTML 表单input类型HTML 表单input属性HTML多媒体 HTML多媒体HTML5 教程 HTML5 教程 从入门到精通HTML5 拖放/拖拽HTML5 语义元素 HTML5 新的 Input 输入类型HTML5 新表单元素HTML5 新的表单属性HTML5 canvas画布HTML5 SVG矢量图形HTML5 Audio(音频)HTML5 Video(视频)HTML5 Web WorkersHTML5 存储HTML5 WebSocketHTML5 IndexedDBHTML5 IndexedDB增删改查HTML 参考手册 HTML 全局属性HTML 事件属性HTML 世界语言代码缩略词ascii码对照表HTML 完整的 ISO-8859-1 参考手册HTML 符号实体参考手册HTML 字符集HTML URL编码表HTML Canvas 参考手册SVG 参考手册HTML 音频/视频 document 参考手册

HTML5 Web Workers

JS是单线程没有多线程,当JS在页面中运行长耗时同步任务的时候就会导致页面假死影响用户体验,从而需要设置把任务放在任务队列中;Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。它的作用就是给JS创造多线程运行环境,允许主线程创建worker线程,分配任务给后者,主线程运行的同时worker线程也在运行,相互不干扰,在worker线程运行结束后把结果返回给主线程。这并不意味着JS语言本身支持了多线程能力,而是浏览器作为宿主环境提供了JS一个多线程运行的环境。

案例

创建了一个简单的 web worker,在后台计数:

简单的 web worker

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 WebWorkers计数器实例-HTML教程www.xuandaima.com</title>
</head>
<body>
    <p>计数: <output id="result"></output></p>
    <button onclick="startWorker()">开始工作</button> 
    <button onclick="stopWorker()">停止工作</button>

    <p><strong>注意:</strong> Internet Explorer 9 及更早 IE 版本浏览器不支持 Web Workers.</p>

    <script>
    var w;

    function startWorker() {
        if(typeof(Worker) !== "undefined") {
            if(typeof(w) == "undefined") {
                w = new Worker("/Template/Test/js/demo_workers.js");
            }
            w.onmessage = function(event) {
                document.getElementById("result").innerHTML = event.data;
            };
        } else {
            document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 Web Workers...";
        }
    }

    function stopWorker()
    {
        w.terminate();
        w = undefined;
    }
    </script>
</body>
</html>

demo_workers.js 文件代码

var i=0;

function timedCount()
{
    i=i+1;
    postMessage(i);
    setTimeout("timedCount()",500);
}

timedCount();

运行代码

支持浏览器

ChromeIEFirefoxsafarioprea

检测浏览器是否支持 Web Worker

在创建 web worker 之前,请检测用户的浏览器是否支持它:

if(typeof(Worker)!=="undefined")
{
    // 是的! Web worker 支持!
    // 一些代码.....
}
else
{
    //抱歉! Web Worker 不支持
}

创建 web worker 文件

现在,让我们在一个外部 JavaScript 中创建我们的 web worker。

在这里,我们创建了计数脚本。该脚本存储于 "demo_workers.js" 文件中:

var i=0;

function timedCount()
{
    i=i+1;
    postMessage(i);
    setTimeout("timedCount()",500);
}

timedCount();

以上代码中重要的部分是 postMessage() 方法 - 它用于向 HTML 页面传回一段消息。

注意注意: web worker 通常不用于如此简单的脚本,而是用于更耗费 CPU 资源的任务。

创建 Web Worker 对象

我们已经有了 web worker 文件,现在我们需要从 HTML 页面调用它。

下面的代码检测是否存在 worker,如果不存在,- 它会创建一个新的 web worker 对象,然后运行 "demo_workers.js" 中的代码:

if(typeof(w)=="undefined")
{
    w=new Worker("demo_workers.js");
}

然后我们就可以从 web worker 发送和接收消息了。

向 web worker 添加一个 "onmessage" 事件监听器:

w.onmessage=function(event){
    document.getElementById("result").innerHTML=event.data;
};

终止 Web Worker

当我们创建 web worker 对象后,它会继续监听消息(即使在外部脚本完成之后)直到其被终止为止。

如需终止 web worker,请使用 terminate() 方法。

w.terminate();
注意terminate方法会释放一些内存空间,但是在页面无重新打开的情况下(关闭页面再重新打开),回在terminate方法结束前的使用内存空间数进行追加。

限制

worker线程的使用有一些注意点

1.同源限制

worker线程执行的脚本文件必须和主线程的脚本文件同源,这是当然的了,总不能允许worker线程到别人电脑上到处读文件吧

2.文件限制

为了安全,worker线程无法读取本地文件,它所加载的脚本必须来自网络,且需要与主线程的脚本同源

3.DOM操作限制

worker线程在与主线程的window不同的另一个全局上下文中运行,其中无法读取主线程所在网页的DOM对象,也不能获取 document、window等对象,但是可以获取navigator、location(只读)、XMLHttpRequest、setTimeout族等浏览器API。

4.通信限制

worker线程与主线程不在同一个上下文,不能直接通信,需要通过postMessage方法来通信。

5.脚本限制

worker线程不能执行alert、confirm,但可以使用 XMLHttpRequest 对象发出ajax请求。

实战场景

个人觉得,Web Worker我们可以当做计算器来用,需要用的时候掏出来摁一摁,不用的时候一定要收起来~

1.加密数据

有些加解密的算法比较复杂,或者在加解密很多数据的时候,这会非常耗费计算资源,导致UI线程无响应,因此这是使用Web Worker的好时机,使用Worker线程可以让用户更加无缝的操作UI。

2.预取数据

有时候为了提升数据加载速度,可以提前使用Worker线程获取数据,因为Worker线程是可以是用 XMLHttpRequest 的。

3.预渲染

在某些渲染场景下,比如渲染复杂的canvas的时候需要计算的效果比如反射、折射、光影、材料等,这些计算的逻辑可以使用Worker线程来执行,也可以使用多个Worker线程,这里有个射线追踪的示例。

4.复杂数据处理场景

某些检索、排序、过滤、分析会非常耗费时间,这时可以使用Web Worker来进行,不占用主线程。

5.预加载图片

有时候一个页面有很多图片,或者有几个很大的图片的时候,如果业务限制不考虑懒加载,也可以使用Web Worker来加载图片,可以参考一下这篇文章的探索,这里简单提要一下。