资讯专栏INFORMATION COLUMN

JavaScript多线程-Web Worker

vpants / 1820人阅读

摘要:但是,单核也能实现多任务同时运行,比如你边听网易云音乐的每日推荐歌曲,边在网易有道云笔记上写博文。比如网易云音乐一边播放音频,一边显示歌词。

JS组成 ECMAScript

ECMAScript规定了JavaScript脚本的核心语法,如 数据类型、关键字、保留字、运算符、对象和语句等,它不属于任何浏览器。

Document Object Model

文档对象模型(DOM)将web页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将HTMLSVGXML文档建模为对象并不是JavaScript语言的一部分。DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。

Browser Object Model

浏览器对象模型(BOM),是用于描述这种对象与对象之间层次关系的模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象.

线程与进程

进程(Process)是系统资源分配和调度的单元。一个运行着的程序就对应了一个进程。一个进程包括了运行中的程序和程序所使用到的内存和系统资源。如果是单核CPU的话,在同一时间内,有且只有一个进程在运行。但是,单核CPU也能实现多任务同时运行,比如你边听网易云音乐的每日推荐歌曲,边在网易有道云笔记上写博文。这算开了两个进程(多进程),那运行的机制就是一会儿播放一下歌,一会儿响应一下你的打字,但由于CPU切换的速度很快,你根本感觉不到,以至于你认为这两个进程是在同时运行的。进程之间是资源隔离的。

那线程(Thread)是什么?线程是进程下的执行者,一个进程至少会开启一个线程(主线程),也可以开启多个线程。比如网易云音乐一边播放音频,一边显示歌词。多进程的运行其实也就是通过进程中的线程来执行的。一个进程下的线程是可以共享资源的,所以在多线程的情况下,需要特别注意对临界资源的访问控制.

浏览器
目前最为流行的浏览器为:`Chrome,IE,Safari,FireFox,Opera.
一个浏览器通常由以下几个常驻的线程:

渲染引擎线程:负责页面的渲染

JS引擎线程:负责JS的解析和执行

定时触发器线程:处理定时事件,比如setTimeout, setInterval

事件触发线程:处理DOM事件

异步http请求线程:处理http请求

需要注意的是,渲染线程和JS引擎线程是不能同时进行的。渲染线程在执行任务的时候,JS引擎线程会被挂起。因为JS可以操作DOM,若在渲染中JS处理了DOM,浏览器可能就懵逼了。
Web Worker 简介

Web Worker (工作线程) 是 HTML5 中提出的概念,Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个多带带的线程中执行费时的处理任务,从而允许主(通常是UI)线程运行而不被阻塞/放慢.

Web Worker可以分为一下几类:

专用线程(Dedicated Worker)

专用线程仅能被创建它的脚本所使用(一个专用线程对应一个主线程)

共享线程(Shared Worker)

共享线程能够在不同的脚本中使用(一个共享线程对应多个主线程)

服务工作线程(Service Workers)

注册在指定源和路径下的事件驱动worker, 可以控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源.

Chrome Workers

一种仅适用于firefoxworker.

Aduio Workers

可以在网络worker上下文中直接完成脚本化音频处理
浏览器兼容性
可以通过caniuse 查看兼容性

Dedicated Worker 兼容性

Shared Worker 兼容性

使用场景

懒加载

文本分析

流媒体数据处理

canvas图形绘制

图像处理

...

限制

同源限制

无法访问DOM

有自己的上下文,无法使用Window对象

workerType 上下文
Dedicated Worker DedicatedWorkerGlobalScope
Shared Worker SharedWorkerGlobalScope
创建线程

检查浏览器是否支持

if (window.Worker) {
    // some code
}

专用线程

@params {String} url 表示worker将执行的脚本的URL,必须遵守同源策略
@params {Object} [options] 创建对象实例时设置的选项属性的对象
@params {Object} [options.type]
@params {Object} [options.name]
@params {Object} [options.credentials]
@returns 创建的worker
const myWorker = new Worker(url[, options]);

示例

// main.js
const myDedicatedWorker = new Worker("./dedicated_worker/worker.js", { name: "dedicatedWorker" });

// worker.js
console.log("success");

共享线程

@params {String} url 表示worker将执行的脚本的URL,必须遵守同源策略
@params {Object} [options] 创建对象实例时设置的选项属性的对象
@params {Object} [options.type]
@params {Object} [options.name]
@params {Object} [options.credentials]
@returns 创建的worker
const myWorker = new SharedWorker(url[, options]);

示例

// main.js
const mySharedWorker = new SharedWorker("./shared_worker/worker.js", { name: "sharedWorker" });

// worker.js
console.log("success");
线程通信

发送信息

@params {Object} message 传递的数据对象
@params {Object} [options] 一个可选的Transferable对象的数组,用于传递所有权.如果一个对象的所有权被转移,在发送它的上下文中将变为不可用(中止),并且只有在它被发送到的worker中可用。
myWorker.postMessage(message, transferList);

接收信息

myWorker.onmessage = function(event) {
    const data = event.data; // 接收到的消息数据
}

专用线程示例

// main.js
const myWorker = new Worker("worker.js");
myWorker.postMessage([10, 20]);
myWorker.onmessage = function (event) {
    console.log(event.data);
}

// worker.js
onmessage(event) {
    console.log(event.data);
    postMessage(event.data[1] - event.data[0]);
}

共享线程示例

// main.js
const myWorker = new SharedWorker("worker.js");
myWorker.port.start();
myWorker.port.postMessage([10, 20]);
myWorker.port.onmessage = function (event) {
    console.log(event.data);
}

// worker.js
connect(event) {
    const port = event.port[0];

    port.onmessage(event) {
        port.postMessage(event.data[1] - event.data[0]);
    }
}
SharedWorker的使用中,我们发现对于SharedWorker实例对象,我们需要通过port属性来访问到主要方法;同时在Worker脚本中,多了个全局的 connect()函数,同时在函数中也需要去获取一个port对象来进行启动以及操作;这是因为,多页页面共享一个SharedWorker线程时,在线程中需要去判断和区,分来自不同页面的信息,这是最主要的区别和原因。

Worker线程中,selfthis都代表子线程的全局对象。对于监听 message事件,以下的四种写法是等同的。

// 写法 1
self.addEventListener("message", function (e) {
    // ...
})

// 写法 2
this.addEventListener("message", function (e) {
    // ...
})

// 写法 3
addEventListener("message", function (e) {
    // ...
})

// 写法 4
onmessage = function (e) {
    // ...
}

示例

关闭线程
myWorker.terminate(); // 主线程中使用
close(); worker线程中使用(推荐)
错误处理
// 主线程
myWorker.onerror = function(event) {
    const lineno = event.lineno;      // 出错的脚本名称
    const filename = event.filename;  // 发生错误的行号
    const message = event.message;    // 对错误的描述
} 
// 不能进行反序列化时触发
myWorker.onmessageerror = function() { ... }  // 专用线程
myWorker.port.onmessageerror function() {...} // 共享线程
外部加载脚本
提供importScript()方法,导入一条或者以上脚本到当前worker的作用域里.
每个脚本中的全局对象都能够被 worker 使用.
importScript("first.js", "second.js");
子进程

Worker可以生成子进程

存在同源限制

Worker中的URL相对于父级Woker所在位置进行解析

嵌入Worker

结构化克隆算法
结构化克隆算法是由HTML5规范定义的用于复制复杂JavaScript对象的算法。通过来自WorkerspostMessage()或使用IndexedDB存储对象时在内部使用。它通过递归输入对象来构建克隆,同时保持先前访问过的引用的映射,以避免无限遍历循环。这一过程可以理解为,在发送方使用类似JSON.stringfy()的方法将参数序列化,在接收方采用类JSON.parse()的方法反序列化。

Error以及Function对象是不能被结构化克隆算法复制的;如果你尝试这样子去做,这会导致抛出DATA_CLONE_ERR的异常

无法克隆DOM

对象的某些特定参数也不会被保留

RegExp对象的lastIndex字段不会被保留

属性描述符,setters 以及 getters(以及其他类似元数据的功能)同样不会被复制。例如,如果一个对象用属性描述符标记为 read-only,它将会被复制为 read-write,因为这是默认的情况下

原形链上的属性也不会被追踪以及复制

Web Worker中可以使用的函数和类

时间相关

clearInterval()
clearTimeout()
setInterval()
setTimeout

Worker 相关

importScripts()
close()
postMessage()

存储相关

Cache
IndexedDB

网络相关

Fetch
WebSocket
XMLHttpRequest

更多

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101391.html

相关文章

  • JavaScript线程机制与事件机制

    摘要:的单线程,与它的用途有关。为了利用多核的计算能力,提出标准,允许脚本创建多个线程,但是子线程完全受主线程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、进程与线程 1.进程 进程是指程序的一次执行,它占有一片独有的内存空间,可以通过windows任务管理器查看...

    godlong_X 评论0 收藏0
  • JavaScript线程机制与事件机制

    摘要:的单线程,与它的用途有关。为了利用多核的计算能力,提出标准,允许脚本创建多个线程,但是子线程完全受主线程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、进程与线程 1.进程 进程是指程序的一次执行,它占有一片独有的内存空间,可以通过windows任务管理器查看...

    BWrong 评论0 收藏0
  • JavaScript线程机制与事件机制

    摘要:的单线程,与它的用途有关。为了利用多核的计算能力,提出标准,允许脚本创建多个线程,但是子线程完全受主线程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、进程与线程 1.进程 进程是指程序的一次执行,它占有一片独有的内存空间,可以通过windows任务管理器查看...

    Taste 评论0 收藏0
  • JavaScript线程机制与事件机制

    摘要:的单线程,与它的用途有关。为了利用多核的计算能力,提出标准,允许脚本创建多个线程,但是子线程完全受主线程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、进程与线程 1.进程 进程是指程序的一次执行,它占有一片独有的内存空间,可以通过windows任务管理器查看...

    wangxinarhat 评论0 收藏0
  • 聊聊webWorker

    摘要:不过,这并不意味着语言本身就支持了多线程,对于语言本身它仍是运行在单线程上的,只是浏览器宿主环境提供的一个能力。主线程与子线程之间也可以交换二进制数据,比如等对象,也可以在线程之间发送。 先看几个例子 本例子是通过通过红点展示地球上的地震带,数据来自于地质探测局通过console.log看到数据运算所耗的时间不使用 webworker No web workers - all on ...

    luffyZh 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<