WebWorker进阶

WebWorker与主线程之间的通信这篇文章主要分享介绍了WebWorker特殊应用场景, 扩展了WebWorker的能力, 为跨页面通信提供了另外一种思路。在上一篇文章里面也有了解到webworker与主线程之间的通信,使用的是一个PostMessage。在上一篇文章中,有个例子是,从主线程到子线程传了一个json,从子线程到主线程传了一个number,由此可见,Webworker与主线程通信之间的通信内容可以是:字符串、对象、二进制或者是任何JavaScript可以表示存储的内容,只要这个内容可以用JavaScript的变量来表示,那么这个内容就可以被PostMessage传输,然后这个传输就是拷贝关系。也就是说在子线程里面到主线程会完全拷贝一份一模一样的,之后再送给需要接收消息的另一方,这就是一个拷贝关系,这个关系主要是为了防止传输过程中出现的意外造成数据的不完整,然后在JavaScript中,一些参数的传递都是一个浅拷贝,浅拷贝违背了子线程和主线程只能通过PostMessage传递消息的原则。所以WebWorker与主线程通信之间的通信关系都是拷贝关系。但是我们需要考虑的一点是,拷贝数据量过大时,拷贝起来是比较消耗性能的,因此WebWorker有一个转移的方式,转移起来只能使用二进制,转移之后当前线程无论是从主到子还是从子到主,转移之后的二进制数据就没有操作权了,接收方才有操作权。 webWorker.postMessage(arrayBuffer, [arrayBuffer]);执行同页面的WebWorkerJavaScript代码要在WebWorker里面执行的代码需要放在同一个文件里。 未知的script 类型,代码不会执行 <script id="samePageWorker" type="unknow"> addEventListener('message', () => { postMessage('send message!'); }, false); </script>二进制读取并开启新的WebWorker const blob = new Blob([document.getElementById('samePageWorker').text]); //把读取文件的内容放到内存中,之后再返回一个内存地址 const url = URL.createObjectURL(blob); /* 获取保存在内存中的文件地址 */ const webWorker = new Worker(url); webWorker.postMessage(123);WebWorker嵌套//主进程起了一个main.js的WebWorker,向它发送了一个Helloconst webWorker = new Worker('./main.js');window.webWorker = webWorker;webWorker.postMessage('Hello');//子进程main.js又起了一个worker然后向下面这个子进程发送了一个message:wordthis.addEventListener('message', event => { console.log('received index.html data', event.data);}, false);const webWorker = new Worker('./index.js');webWorker.postMessage('Word');//在index.js也就是最里层的WebWorker加了一个消息监听事件,接收到了下面这个数组this.addEventListener('message', event => { console.log('received main data', event.data);}, false)};Shared WebWorker(跨页面通信)不能使用console ...

July 10, 2019 · 1 min · jiezi

初始WebWorker

基本概念JS单线程:我们都知道JavaScript它是一个单线程的语言,同一时间只能做一件事。比如:在浏览器中,某一时刻我们在操作DOM,你们这个时刻我们就不能去运行JavaScript代码,反过来也是,当我们在运行JavaScript代码的时候,我们也不能去操作DOM,这个也就是JS的单线程。为什么要JS成单线程?因为在浏览器环境下,如果是多线程的,也就是操作DOM和运行JavaScript代码是并行处理的话,假如某个时刻,浏览器正在绘制DOM,但是这个时候的JavaScript代码改变了DOM,这样就会造成一个不一致,因此JS就被设计成了一门单线程语言。 虽然JS是单线程,但是它的宿主,我们的浏览器环境(node环境)它是一个多线程的,在浏览器和node里面只有一条JS线程,但是还有很多其他的线程。以浏览器为例,浏览器的常驻线程(如下)大概有前三个:第一个,UI线程,也就是DOM浏览器元素的回流和重绘,这个UI线程与JavaScript线程是互斥的。第二个就是JavaScript线程,单线程的运行JS代码。第三个是GUI线程,它主要是处理与用户交互的一些逻辑,比如点击某一个元素,拖动了或者缩放了这个就是由GUI线程处理的。除此之外还有NetWorker线程,网络线程,发送ajax请求,发送http请求都是走的network线程。还有File线程,读取文件。还有一个定时器线程。 UI线程 - 回流和重绘 - 与Javascript线程互斥JavaScript线程 - 单线程运行JavaScriptGUI线程 - 交互线程Network线程File线程定时器线程这里可能会有一个问题是ajax请求对于JS来说是异步的,但是JavaScript是单线程的,这样就涉及到了一个基于事件的驱动。当我们发起一个网络请求时,浏览器会把这一部分网络请求交给network线程去处理,然后JavaScript线程等待network的指令驱动。在没有代码要运行的情况下,JavaScript线程始终是空闲的,有了事件驱动之后,它会一直处于一个轮询的状态(Event Loop),浏览器会不断查询目前是否有JavaScript线程需要运行,如果有就运行,没有就保持闲置。当一个网络请求发送出去,这个时候的JavaScript线程是处于闲置的,但是浏览器还是会不停的询问,当network线程结束后,浏览器发现有新的JavaScript代码需要执行,它就会驱动JavaScript的线程去处理网络请求返回的结果,这个就是JS 基于事件驱动的模型。 Event Loop(事件轮询图) 异步是将耗时比较长的任务放置到Event Queue 事件队列的尾部。 WebWorkerWebWorker为了解决浏览器假死这个问题而孕育而生的一项新技术。它是多线程模型,也是基于宿主。它属于JavaScript线程中的一个子线程,它完全受主线程控制,但是在WebWorker里面是不能操作DOM的。因为上面提到的UI线程和JavaScript线程是互斥的,这个互斥也就保证了DOM的唯一性,因此主的基调不能改变,但是需要有一个新的线程来分担繁杂的计算任务,这个也就是WebWorker。 浏览器的兼容性 应用场景WebWorker是为了处理影响UI线程的JavaScript运算。因为在同一时刻,UI线程和JavaScript线程只能有一个在运行,如果这个时候JS的线程承担过多运算的话,它的耗时就变得很长,这个时候的UI线程是没有反应的,这样就造成了页面的假死。 WebWorker特点一旦新建就会始终运行,不会被主线程打断。即使主线程卡死了,WebWorker依然在运行。同源限制,对于同一个WebWorker来讲,只有同源的网页才能够访问。不能操作和访问DOM(window、document),因为要保证DOM 的唯一性。不能使用包含交互的全局方法(alert、confirm),但是可以使用XMLHttpRequest、setTimeout、setInterval不能读取本地文件(不止WebWorker不能读取,JavaScript主线程也不能读取),出于安全性的考虑,浏览器是不允许js读取本地文件的。WebWorker分为两个:dedicated web worker(专用线程) ,只有一个网址一个页面可以使用这个线程和 shared web worker(共享线程),多个同源的网页可以共享一个WebWorker,这样为跨页面通信提供了一种可能。基本用法创建WebWorker const webWorker = new Worker('main.js');let result = 0;const fibonacci = (n) => { if (n <= 1) return 1; return fibonacci(n - 1) + fibonacci(n - 2);}result = fibonacci(10);console.log('result', result);向WebWorker发送消息(数据) webWorker.postMessage({ number : 10 });WebWorker接收消息 webWorker.addEventListener('message', event => { console.log('received webworker data', event.data);}, false);WebWorker发送消息(返回数据) ...

July 9, 2019 · 1 min · jiezi

11JavaScript-线程机制与事件机制

JavaScript线程机制与事件机制一、进程与线程进程(process)程序的一次执行,它占有一片独有的内存空间。可以通过windows任务管理器查看进程。线程(thread)是进程内的一个独立执行单元。是程序执行的一个完整流程。是CPU的最小调度单元。进程与线程图解 相关知识应用程序必须运行在某个进程的某个线程上。一个进程中至少有一个运行的线程:主线程,进程启动后自动创建。一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的。一个进程内的数据可以供其中的多个线程中直接共享。多个进程之间的数据是不能直接共享的。线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用。相关问题(1)何为多进程与多线程? 多进程运行:一个应用程序可以同时启动多个实例运行。多线程:在一个进程内,同时有多个线程运行。(2)比较单线程与多线程? 多线程 优点:能有效提升CPU的利用率。缺点: 创建多线程开销。线程间切换开销。死锁与状态同步问题。单线程 优点:顺序编程简单易懂。缺点:效率低。(3)JS是单线程还是多线程? JS是单线程运行的。但是使用H5中的 Web Workers可以多线程运行。(4)浏览器运行是单线程还是多线程? 浏览器都是多线程运行的。(5)浏览器运行是单进程还是多进程? 有的是单进程: 老版Firefox老版IE有的是多进程: Chrome新版Firefox新版IE如何查看浏览器是否是多进程运行的呢? 任务管理器==>进程二、浏览器内核(1)浏览器内核是支撑浏览器运行的最核心的程序。 (2)不同的浏览器内核不一样: Chrome,Safari:webkitFirefox:GeckoIE:Trident360,搜狗等国内浏览器:Trident+webkit(3)内核由很多模块组成: 主线程 js引擎模块:负责js程序的编译与运行。html,css文档解析模块:负责页面文本的解析。DOM/CSS模块:负责DOM/CSS在内存中的相关处理。布局和渲染模块:负责页面的布局和效果的绘制(内存中的对象)分线程 定时器模块:负责定时器的管理。DOM事件响应模块:负责事件的管理。网络请求模块:负责服务器请求(常规/ajax)。三、定时器引发的思考(1)定时器真是定时执行的吗? 定时器并不能保证真正定时执行。一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)。<button id="btn">启动定时器</button>document.getElementById('btn').onclick = function () { var start = Date.now() console.log('启动定时器前...') setTimeout(function () { console.log('定时器执行了', Date.now()-start) }, 200) console.log('启动定时器后...')} 给上面回调函数加一个长时间的任务: document.getElementById('btn').onclick = function () { var start = Date.now() console.log('启动定时器前...') setTimeout(function () { console.log('定时器执行了', Date.now()-start) }, 200) console.log('启动定时器后...') // 做一个长时间的工作 for (var i = 0; i < 1000000000; i++) {}}结果: ...

June 27, 2019 · 2 min · jiezi