欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HTML 5 Web Workers

程序员文章站 2022-07-03 16:58:54
...

    单线程:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。简单的说就是处理事务的任务链,当只有一条链,所有的事情都在这一条链上执行时,那就是单线程。

        优点:单线程较多线程来说,系统稳定、扩展性极强、软件丰富。

        缺点:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)。

    多线程:有多条链时,那就是多线程了,当然并不是说多条线并行,而是说有一条主线程,处理整个程序任务的主方向的链,而其链上又有许许多多的分支,就像树枝那样,这样,既有了主线程去处理那些主要任务,又有了那些细小线程去处理耗时费力任务,从而让界面看起来更加流畅。


Web Workers简介:

    我们都知道JavaScript这个语言在执行的时候是采用单线程进行执行的,也就是说在同一时间只能做一件事,这也和JavaScript语言有很大的关系,采用同步执行的方式进行运行,如果出现阻塞,那么后面的代码将不会执行。

    JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行,但是浏览器有很多线程,是多线程的,当js线程在执行时,浏览器可以根据需求开相应的线程进行处理。

    HTML5则提出了web Worker标准,表示JavaScript允许有多个线程,但是子线程完全受主线程的控制,切子线程不能操作DOM,只有主线程可以操作DOM,所以以主线程为主的单线程执行原理成了JavaScript这门语言的核心。

    JavaScript多线程是在原有主线程之外分了worker线程出来,但是子线程完全受主线程控制,且不得操作DOM。因为Worker线程不能直接访问和操作页面中的DOM属性,如果Worker线程需要访问页面中的某个DOM节点,必须通过postMessage API发消息给主线程,主线程在收到消息后获取页面中的某个DOM节点的属性,再通过postMessage的方式回传给Worker线程,这样就避免了冲突。

什么是Web Workers?

    在JavaScript单线程执行的基础上,开启一个子线程,进行程序处理,而不影响主线程的执行,当子线程执行完毕之后再回到主线程上,在这个过程中并不影响主线程的执行过程。

    允许JavaScript创建多个线程,但是子线程完全受主线程控制,且不得操作DOM从而,可以用webWorker来处理一些比较耗时的计算

    浏览器支持:

    所有主流浏览器均支持 web worker,除了 Internet Explorer。

    检测浏览器是否支持:

if(typeof(Worker)!=="undefined")
  {
  // Yes! Web worker support!
  // Some code.....
  }
else
  {
  // Sorry! No Web Worker support..
  }


使用 web worker

操作说明:    

    WEB主线程:

        1. 通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。

        2. 通过worker.postMessage( data ) 方法来向worker发送数据。

        3. 绑定worker.onmessage方法来接收worker发送过来的数据。

        4. 可以使用 worker.terminate() 来终止一个worker的执行。

    worker子线程:

        1. 通过postMessage( data ) 方法来向主线程发送数据。

        2. 绑定onmessage方法来接收主线程发送过来的数据。

代码说明:

    1. 创建线程

        通过开启一个新的线程来执行需要开多线程的这段代码,将代码放在一个单独的JS文件中,在主线程执行以下代码,在创建线程的时候需要给实例化的Worker传入唯一一个参数,指向一个JavaScript文件资源的url或者Blob对象(Blob对象就是一个包含有只读原始数据类文件对象),调用这个构造函数之后,一个线程就被创建了,如下:

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

    2. 编写子线程JS文件

    子线程JS文件注意:

        1.子线程能进行计算,不能进行 DOM BOM操作

//子线程可以直接进行计算
//主线程html页面
var oW = new Worker('b.js');
oW.postMessage(alert);

//子线程b.js
this.onmessage = function(ev){
    console.log(ev.data+5);    //  10  
};
//可以利用子线程成为我们进行一些计算
var oW = new Worker('c.js');
oW.postMessage(12);  //向子线程发送数据
oW.onmessage = function(ev){ //接收字线程发送过来的数据
alert(ev.data);  //17
};

//子线程c.js
this.onmessage = function(ev){  //接收主线程发送过来的数据
this.postMessage(ev.data+5);  //向主线程发送数据
};

        2.子线程不能跨域,文件需放在同路径中

        3.子线程不能套子线程

        4.子线程 不和主线程共享数据,而是复制一份儿 哪怕是对象

//变量
//主线程html页面
var oW = new Worker('d.js');
var a = 12;
oW.postMessage(a);
oW.onmessage = function(ev){
    alert(ev.data);//17
};
alert('主线程:'+a); //12

//子线程d.js
this.onmessage = function(ev){
    this.postMessage(ev.data+5);
};
//对象
//主线程html页面
var oW = new Worker('e.js');
var arr = [12,5,8];
oW.postMessage(arr);
oW.onmessage = function(ev){
    alert('子线程'+ev.data);//[101,5,8]
};
alert('主线程'+arr);//12,5,8

//子线程e.js
this.onmessage = function(ev){
    ev.data[0] = 101;
    console.log(ev.data);
    this.postMessage(ev.data);
};

    3. 线程通信

        webworker的基本原理就是在当前的主线程中加载一个只读文件来创建一个新的线程,两个线程同时存在,且互不阻塞,并且在子线程与主线程之间提供了数据交换的接口postMessageonmessage。来进行发送数据和接收数据。其数据格式可以为结构化数据(JSON等)

    4. 传递消息:当我们创建了一个worker实例之后,可以通过如下两种方式来发送数据

var worker = new Worker("worker.js");  //实例化对象

//第一种传递方式
worker.postMessage(message,taransferList);

//第二种传递方式
worker.postMessage({ 
     operation: "list_all_users", 
     //ArrayBuffer object 
     input: buffer, 
     threshold: 0.8, 
}, [buffer]);

    5. 接收消息:同时我们如果需要接收某个线程传来的数据可以使用onmessage来进行接收,方法如下:

//方法一
worker.onmessage = function(event){
    var data = event.data;        //通过event.data来获取传入的参数
}

//方法二
worker.addEventListener("message",target);

    6. 异常处理

worker.onerror = function(e){
    console.log("error at "+e.filename ":" + e.lineno + e.message)
}

    7. 结束worker

worker.terminate();

    8. 载入工具类函数

    需要注意的是importScripts是同步方法,一旦importScripts方法返回就可以开始使用载入的脚本,而不需要回调函数。

importScripts("./utils/base64.js","./utils/map.js"...)

    

Worker作用域

当我们创建一个新的worker时,改代码会运行在一个全新的javascript的环境中(WorkerGlobalScope)运行,是完全和创建worker的脚本隔离,这时我们可以吧创建新worker的脚本叫做主线程,而被创建的新的worker叫做子线程。

WorkerGlobalScope是worker的全局对象,所以它包含所有核心javascript全局对象拥有的属性如JSON等,window的一些属性,也拥有类似于XMLHttpRequest()等。

但是我们所开启的新的worker也就是子线程,并不支持操作页面的DOM。


webworker 和 DOM

由于webworker 位于外部文件中,无法访问JavaScript对象(DOM对象、window对象、document对象、parent对象)

web worker可以做什么

    1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信

    2.可以在worker中通过importScripts(url)加载另外的脚本文件

    3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()

    4.可以使用XMLHttpRequest来发送请求

    5.可以访问navigator的部分属性

web worker的局限性

    1.不能跨域加载JS

    2.worker内代码不能访问DOM

    3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行

    4.不是每个浏览器都支持这个新特性


相关标签: web worker html5