WebWorker 100%前端基础应用

前言:

    本文为前端开发人员特别编辑,避免过多的原生理论、后台操作以及其他知识面的讲解。

    适合您作为快速入门上手教程使用。

    如有纰漏,还望在评论中提出,我将及时更正。

    感谢您观看本文章教程,祝您工作生活愉快!^_^


注意事项:

    本文中所有链接除引用处会提到外,文章最后也会统一提示。

    (本文不包含 SharedWorker内容)


简要介绍


什么是WebWorker?

    WebWorker是多线程机制在JavaScript中的实现。

    WebWorker与setTimeout或setInterval的区别在于,它是真正多线程的,而非单线程延迟异步执行。


WebWorker的兼容性怎么样?

    这个问题是非常重要的一个问题,毕竟一项新技术需要足够的支持程度和适合的应用场景才值得去学习使用。

WebWorker 100%前端基础应用_第1张图片

图片来源:http://caniuse.com/#search=WebWorker

    从上图我们可以得知,IE从第十个版本开始支持此API,安卓则是4.4系统版本开始支持。Opera Mini的占有率较低,故我们在此可以直接忽略。

    兼容性非常不错!全球支持率达到88.25%,中国环境下支持率也已经达到了75.35%。综合评分:A级。


WebWorker的浏览器实现原理是怎样的?

    在原先的JavaScript运行线程、GUI线程和事件线程外,每new一个新的Worker对象,浏览器都会为其单独开启一个线程。


WebWorker和普通JavaScript执行环境有什么区别?

    1.不能访问DOM。

    2.global对象的指向有变更。Window类型的window对象被DedicatedWorkerGlobalScope类型的self对象所取代。即,我们一般用的window需要改写成self。

    3.只能访问部分navigator对象内的数据。

    4.内置了importScripts函数,代替了DOM中的script标签引用脚本机制。(不能跨域访问脚本)


简单示例


WebWorker(外部环境)的示例:

var worker = new Worker("test.js");

worker.addEventListener("message", function (e) {
    // 接收到了数据
    console.log(e.data);
});

worker.addEventListener("error", function(e) {
    // 发生了错误
});

// 向Worker环境内部发送数据
worker.postMessage("hi");

// 立即停止Worker,不管它在干什么
worker.terminate();
    以上代码简单的表述了运行Worker所需要的一切步骤。

    1.首先,我们用了一个test.js,它是我们专门为Worker环境写的一个处理用脚本文件。

    2.然后分别监听了message事件和error事件,用来处理接收到Worker传出来的数据以及错误信息。

    3.搞定这些后,我们向Worker内部发送一条数据。另外,不用担心此时test.js还未加载进来的问题,这个浏览器会帮我们搞定。

    4.最后,停止Worker。(注意!这并不是标准流程,这里只是为了简单演示用。实际上这个函数只在极端情况下需要立即停止Worker处理才会调用)


test.js(内部环境)的示例:

var a = 0;

self.addEventListener("message", function (e) {
    setInterval(function () {
        a++;
        postMessage(e.data + a);
        if (a == 10) {
            self.close();
        }
    }, 1000);
}, false);

    为了方便理解,我们可以把test.js里的脚本内容当做是被包在一个闭包内的,所有的变量、函数以及对全局的修改都无法应用到外部环境。

    1.首先我们定义了一个变量 a 。

    2.然后监听了message事件,以用来得到外部环境向内部环境所传递的数据。

    3.在接收到数据以后,我们开启一个定时器,每隔一秒向外部环境传递一次信息。

    4.当传递了10次以后,我们在内部停止整个worker的运行,内部环境下的close函数与外部环境下的terminate函数作用一致。


常见错误:postMessage数据无法被复制。

原因分析:

    不论是外部环境向内部环境 或者是 内部环境向外部环境传递任何数据,都不再是简单的指针指向就完事了。

    因为运行在不同的线程中,因此数据的传输是采用复制法。

    因为运行的JavaScript的环境不同,因此有些类型、数据等在内部环境中是不存在的,故此无法被复制。

    举个例子,DOM对象。(原因是,内部环境中没有绑定DOM相关类型以及其他数据)

解决方案:

    请使用安全的数据类型,比如:

    Object、TypedArray、Number、String、Boolean、Array。

    在传递浏览器内部类型对象时,最好简单的做一个测试,用以判断此类型是否安全。


延伸扩展


如何将动态生成的脚本作为Worker使用?

    此时,我们就可以考虑一下Blob类型以及URL.createObjectURL函数了。

var script = "console.log(\"yes!\");"
var workerBlob = new Blob([script], { type: "text/javascript" });
var url = URL.createObjectURL(workerBlob);
var worker = new Worker(url);
   1.我们只需要将动态生成的脚本转换成Blob对象。

    2.然后给这个Blob对象创建一个URL。

    3.最后我们就可以将这个创建好的URL作为地址传给Worker的构造函数了。



参考引用:

兼容性表 - http://caniuse.com/#search=WebWorker

Blob类型说明 - https://developer.mozilla.org/zh-CN/docs/Web/API/Blob

URL.createObjectURL函数说明 - https://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL

你可能感兴趣的:(JavaScript,多线程,html5,异步,webworker)