先看几个例子

结论:是? // 带着思考看下去

背景

JavaScript引擎是单线程运行的,JavaScript中耗时的I/O操作都被处理为异步操作,它们包括键盘、鼠标I/O输入输出事件、窗口大小的resize事件、定时器(setTimeout、setInterval)事件、Ajax请求网络I/O回调等。当这些异步任务发生的时候,它们将会被放入浏览器的事件任务队列中去,等到JavaScript运行时执行线程空闲时候才会按照队列先进先出的原则被一一执行,但终究还是单线程。

虽然JS运行在浏览器中,是单线程的,每个window一个JS线程,但浏览器不是单线程的,例如Webkit或是Gecko引擎,都可能有如下线程:

javascript引擎线程

界面渲染线程

浏览器事件触发线程

Http请求线程

很多人觉得异步(promise async/await),都是通过类似event loop在平常的工作中已经足够,但是如果做复杂运算,这些异步伪线程的不足就逐渐体现出来,比如settimeout拿到的值并不正确,再者假如页面有复杂运算的时候页面很容易触发假死状态,

为了有多线程功能,webworker问世了。不过,这并不意味着 JavaScript语言本身就支持了多线程,对于JavaScript 语言本身它仍是运行在单线程上的,Web Worker只是浏览器(宿主环境)提供的一个能力/API。

简介

Web Worker 是HTML5标准的一部分,这一规范定义了一套API,它允许一段JavaScript程序运行在主线程之外的另外一个线程中。工作线程允许开发人员编写能够长时间运行而不被用户所中断的后台程序, 去执行事务或者逻辑,并同时保证页面对用户的及时响应,可以将一些大量计算的代码交给web worker运行而不冻结用户界面,后面会有案例介绍

类型

Web workers可分为两种类型:专用线程dedicated web worker,以及共享线程shared web worker。 Dedicated web worker随当前页面的关闭而结束;这意味着Dedicated web worker只能被创建它的页面访问。与之相对应的Shared web worker可以被多个页面访问。在Javascript代码中,“Work”类型代表Dedicated web worker,而“SharedWorker”类型代表Shared web worker。

而Shared Worker则可以被多个页面所共享(同域情况下)

如何创建

Web Worker的创建是在主线程当中通过传入文件的url来实现的。如下所示:

let webworker = new Worker('myworker.js');

返回的是webworker实例对象,该对象是主线程和其他线程的通讯桥梁

主线程和其他线程可以通过

onmessage: 监听事件

postmessage: 传送事件

相关的API进行通讯

案例代码如下

//主线程 main.js

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

worker.onmessage = function(event){

// 主线程收到子线程的消息

};

// 主线程向子线程发送消息

worker.postMessage({

type: "start",

value: 12345

});

//web worker.js

onmessage = function(event){

// 收到

};

postMessage({

type: "debug",

message: "Starting processing..."

});

如何终止

如果在某个时机不想要 Worker 继续运行了,那么我们需要终止掉这个线程,可以调用 在主线程worker 的 terminate 方法 或者在相应的线程中调用close:

// 方式一 main.js 在主线程停止方式

var worker = new Worker('./worker.js');

...

worker.terminate();

// 方式二、worker.js

self.close()

错误机制

提供了onerror API

worker.addEventListener('error', function (e) {

console.log('MAIN: ', 'ERROR', e);

console.log('filename:' + e.filename + '-message:' + e.message + '-lineno:' + e.lineno);

});

// event.filename: 导致错误的 Worker 脚本的名称;

// event.message: 错误的信息;

// event.lineno: 出现错误的行号;

sharedWorker

对于 Web Worker ,一个 tab 页面只能对应一个 Worker 线程,是相互独立的;

而 SharedWorker 提供了能力能够让不同标签中页面共享的同一个Worker脚本线程;

当然,有个很重要的限制就是它们需要满足同源策略,也就是需要在同域下;

在页面(可以多个)中实例化Worker 线程:

// main.js

var myWorker = new SharedWorker("worker.js");

myWorker.port.start();

myWorker.port.postMessage("hello, I'm main");

myWorker.port.onmessage = function(e) {

console.log('Message received from worker');

}

// worker.js

onconnect = function(e) {

var port = e.ports[0];

port.addEventListener('message', function(e) {

var workerResult = 'Result: ' + (e.data[0]);

port.postMessage(workerResult);

});

port.start();

}

父子线程

线程中再创建线程

环境与作用域

在Worker线程的运行环境中没有window全局对象,也无法访问DOM对象,所以一般来说他只能来执行纯 JavaScript的计算操作。但是,他还是可以获取到部分浏览器提供的API 的:

setTimeout(), clearTimeout(), setInterval(), clearInterval():有了设计个函数,就可以在 Worker: 线程中可以再创建worker;

XMLHttpRequest: 对象:意味着我们可以在 Worker 线程中执行 ajax 请求;

navigator对象:可以获取到 ppName,appVersion,platform,userAgent等信息;

location对象(只读):可以获取到有关当前URL 的信息;

Application Cache

indexedDB

WebSocket、

Promise、

库或外部脚本引入和访问

在线程中,提供了importScripts方法

如果线程中使用了importScripts 一般按照以下步骤解析

1、解析 importScripts方法的每一个参数。

2、如果有任何失败或者错误,抛出 SYNTAX_ERR 异常。

3、尝试从用户提供的 URL 资源位置处获取脚本资源。

4、对于 importScripts 方法的每一个参数,按照用户的提供顺序,获取脚本资源后继续进行其它操作。

// worker.js

importScripts('math_utilities.js');

onmessage = function (event)

{

var first=event.data.first;

var second=event.data.second;

calculate(first,second); // calculate 是math_utilities.js中的方法

};

也可以一次性引入多个

//可以多起一次传入

importScripts('script1.js', 'script2.js');

XMLHttpRequest

onmessage = function(evt){

var xhr = new XMLHttpRequest();

xhr.open("GET", "serviceUrl"); //serviceUrl为后端j返回son数据的接口

xhr.onload = function(){

postMessage(xhr.responseText);

};

xhr.send();

}

jsonp

// 设置jsonp

function MakeServerRequest()

{

importScripts("http://SomeServer.com?jsonp=HandleRequest");

}

// jsonp回调

function HandleRequest(objJSON)

{

postMessage("Data returned from the server...FirstName: "

+ objJSON.FirstName + " LastName: " + objJSON.LastName);

}

// Trigger the server request for the JSONP data

MakeServerRequest();

通讯原理

从一个线程到另一个线程的通讯实际上是一个值拷贝的过程,实际上是先将数据JSON.stringify之后再JSON.parse。主线程与子线程之间也可以交换二进制数据,比如File、Blob、ArrayBuffer等对象,也可以在线程之间发送。但是,用拷贝方式发送二进制数据,会造成性能问题。比如,主线程向子线程发送一个50MB文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript允许主线程把二进制数据直接转移给子线程,转移后主线程无法再使用这些数据,这是为了防止出现多个线程同时修改数据的问题,这种转移数据的方法,叫做Transferable Objects。

不过现在很多浏览器支持transferable objects(可转让对象) ,这个技术是零拷贝转移,能大大提升性能,

可以指定传送的数据全都是零拷贝

var abBuffer = new ArrayBuffer(32);

aDedicatedWorker.postMessage(abBuffer, [abBuffer]);

也可以 指定某个是 使用 零拷贝

var objData = {

"employeeId": 103,

"name": "Sam Smith",

"dateHired": new Date(2006, 11, 15),

"abBuffer": new ArrayBuffer(32)

};

aDedicatedWorker.postMessage(objData, [objData.abBuffer]);

工作线程生命周期

工作线程之间的通信必须依赖于浏览器的上下文环境,并且通过它们的 MessagePort对象实例传递消息。每个工作线程的全局作用域都拥有这些线程的端口列表,这些列表包括了所有线程使用到的MessagePort对象。在专用线程的情况下,这个列表还会包含隐式的 MessagePort 对象。

每个工作线程的全局作用域对象 WorkerGlobalScope还会有一个工作线程的线程列表,在初始化时这个列表为空。当工作线程被创建的时候或者拥有父工作线程的时候,它们就会被填充进来。

最后,每个工作线程的全局作用域对象WorkerGlobalScope 还拥有这个线程的文档模型,在初始化时这个列表为空。当工作线程被创建的时候,文档对象就会被填充进来。无论何时当一个文档对象被丢弃的时候,它就要从这个文档对象列举里面删除出来。

性能测试

初始化测试

// 部分机器webwoker初始化时间

Macbook Pro: 2 workers, 0.4 milliseconds on average

Macbook Pro: 4 workers, 0.6 milliseconds on average

Nexus 5: 2 workers, 6 milliseconds on average

Nexus 5: 4 workers, 15 milliseconds on average (border-line UI jank)

传输速度测试

1、普通json/object

2、tranferable objects

可见 transferable objects传输速度要高很多

部分典型的应用场景如下

1) 使用专用线程进行数学运算

Web Worker最简单的应用就是用来做后台计算,而这种计算并不会中断前台用户的操作

2) 图像处理

通过使用从或者元素中获取的数据,可以把图像分割成几个不同的区域并且把它们推送给并行的不同Workers来做计算

3) 大量数据的检索

当需要在调用 ajax后处理大量的数据,如果处理这些数据所需的时间长短非常重要,可以在Web Worker中来做这些,避免冻结UI线程。

4) 背景数据分析

由于在使用Web Worker的时候,我们有更多潜在的CPU可用时间,我们现在可以考虑一下JavaScript中的新应用场景。例如,我们可以想像在不影响UI体验的情况下实时处理用户输入。利用这样一种可能,我们可以想像一个像Word(Office Web Apps 套装)一样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等。

限制

1、不能访问DOM和BOM对象的,Location和navigator的只读访问,并且navigator封装成了WorkerNavigator对象,更改部分属性。无法读取本地文件系统

2、子线程和父级线程的通讯是通过值拷贝,子线程对通信内容的修改,不会影响到主线程。在通讯过程中值过大也会影响到性能(解决这个问题可以用transferable objects)

3、并非真的多线程,多线程是因为浏览器的功能

4、兼容性

5 因为线程是通过importScripts引入外部的js,并且直接执行,其实是不安全的,很容易被外部注入一些恶意代码

6、条数限制,大多浏览器能创建webworker线程的条数是有限制的,虽然可以手动去拓展,但是如果不设置的话,基本上都在20条以内,每条线程大概5M左右,需要手动关掉一些不用的线程才能够创建新的线程(相关解决方案)

7、js存在真的线程的东西,比如SharedArrayBuffer

js的多线程库

webworker应用场景_聊聊webWorker相关推荐

  1. webworker应用场景_初始WebWorker

    基本概念 JS单线程:我们都知道JavaScript它是一个单线程的语言,同一时间只能做一件事.比如:在浏览器中,某一时刻我们在操作DOM,你们这个时刻我们就不能去运行JavaScript代码,反过来 ...

  2. webworker应用场景_典型应用场景 · OpenResty最佳实践-最新版 · 看云

    # 典型应用场景 可以这样说,任何一个开发语言.开发框架,都有它存在的明确目的,重心是为了解决什么问题.没有说我们学习一门语言或技术,就可以解决所有的问题.同样的,`OpenResty`的存在也有其自 ...

  3. python闭包的应用场景_聊聊Python闭包-阿里云开发者社区

    Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西. 闭包的概念 我们尝试从概念上去理解一下闭包. 在一些语言中,在函数中可以(嵌套)定义另一个 ...

  4. webworker应用场景_JavaScript 工作原理之七-Web Workers 分类及 5 个使用场景

    Web Workers 分类及 5 个使用场景 这是 JavaScript 工作原理的第七章. 本系列持续更新中,Github 地址请查阅这里. 现在,我们将会剖析 Web Workers:我们将会综 ...

  5. threadlocal使用场景_深入剖析ThreadLocal

    点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达 朋友们在遇到线程安全问题的时候,大多数情况下可能会使用synchronized关键字,每次只允许一个线程进入锁定的方法或代码块,这样就可以保 ...

  6. 异步通信在生活中的例子_聊聊工作中经常遇到的“异步”,你掌握了多少

    在我们编程的时候,经常会遇到一个概念--异步,诸如异步通信,异步线程,异步代码,异步调用,异步编程等等,那么 什么是异步呢? 为什么要异步? 异步的典型场景是什么? 如何使用异步呢? ...... 异 ...

  7. python 单元测试_聊聊 Python 的单元测试框架(一):unittest

    本文首发于 HelloGitHub 公众号,并发表于 Prodesire 博客. 前言 说到 Python 的单元测试框架,想必接触过 Python 的朋友脑袋里第一个想到的就是 unittest. ...

  8. pytest测试框架_聊聊 Python 的单元测试框架(三):最火的 pytest

    本文首发于 HelloGitHub 公众号,并发表于 Prodesire 博客. 一.介绍 本篇文章是<聊聊 Python 的单元测试框架>的第三篇,前两篇分别介绍了标准库 unittes ...

  9. python中计算带分数_聊聊 python 数据处理全家桶(Redis篇)

    作者:星安果 来源:AirPython 前面两篇文章聊到了 python 处理 Mysql.Sqlite 数据库常用方式,本篇文章继续说另外一种比较常用的数据存储方式:Redis Redis:Remo ...

  10. 嵌入式系统分类及其应用场景_词嵌入及其应用简介

    嵌入式系统分类及其应用场景 Before I give you an introduction on Word Embeddings, take a look at the following exa ...

最新文章

  1. 读书笔记2013第13本:《怎样解题》
  2. 不要再自己封装各种Util工具类了,这款神仙级框架你值得拥有!
  3. 为SharePoint 2010创建Application Page
  4. (chap6 Http首部) 通用首部字段 Connection
  5. edittext 选中焦点在最后_安卓开发中EditText的焦点改变处理(获取焦点和失去焦点交互变化)...
  6. c语言ad采样程序思路,单片机AD采样程序及其寄存器讲解
  7. 实时数仓入门训练营:Hologres性能调优实践
  8. ecs服务器数据迁移_某国际物流集团的云迁移解决方案
  9. Win7下部署Lepus企业级MySQL数据库监控
  10. 安卓股票悬浮窗_股票悬浮窗的安卓应用
  11. javascript征途笔记
  12. linux系统开启ntp服务器配置,Linux系统 NTP服务器配置详解
  13. 青果教务php,拟物校园 | 拟物校园,一个高校教务系统爬虫,现支持正方教务、青果教务。...
  14. 使用Python进行多个机器学习模型、多个评价指标表格绘制(AUC、敏感度、特异度、F1值、约登指数、MCC、Kappa等)
  15. 海湾主机汉字注释表打字出_海湾消防主机字根表-海湾消防主机
  16. matlab--找两条曲线交点并标注于图上的方法
  17. BP 供应商创建与修改
  18. JAVA常用基础API(经典实例)
  19. 视频会议再添猛将:视源股份推出有“情怀”的MAXHUB会议平台
  20. 优思学院|“丰田生产方式“和“福特生产方式”的区别

热门文章

  1. Android FFmpeg视频播放器一解封装
  2. SAP 系统图片修改以及 ABAP屏幕图片(大小调整)自适应设置
  3. 80老翁谈人生(284):沃森参与打击网络犯罪
  4. 老王的JAVA基础课:第3课 IDEA的安装和使用
  5. php 处理eml,php读取eml范例、php解析eml、eml解析成网页
  6. PS3主机今日发售 附官方问答
  7. 【B站】陈睿:令人刮目相看的年轻一代
  8. matlab连接mysql有什么用_MATLAB连接SQLServer和MySql数据库
  9. Retrofit详解
  10. 过桥问题--马儿赛跑问题--智力题