浏览器JavaScript的多线程与web worker

目录

一,浏览器的多线程讨论

二,浏览器web worker,真正的多线程

1. web worker详解

 2. 使用限制

3.使用场景


一,浏览器的多线程讨论

我们都知道浏览器端JavaScript是以单线程的方式执行的,也就是说JavaScript和UI渲染占用同一个主线程,那就意味着,如果JavaScript进行高负载的数据处理,UI渲染就很有可能被阻断,浏览器就会出现卡顿,也就是常说的假死

为了解决这些问题,JavaScript也是提供了异步操作,例如setTimeout,setInterval,ajax,i/o等,例如settimeout,会将计时交给计时线程中,然后继续在消息队列中依次拿任务执行,当计时线程完成后会将执行后的回调函数(任务)添加到消息队列中

就想流水线一样,如图

 

但是!我们又说浏览器js是单线程的,而例如setTimeout是放在计时线程中的,是不是有点自我矛盾的感觉

其实,setInterval和setTimeout并不是js的多线程,这两个函数根本上其实是事件触发函数,想证明setInterval和setTimeout不是多线程很简单,你可以试试这样一段代码

setTimeout(function() {  
    while(true){}  
}, 0)  
setTimeout(function() {  
    alert("foo")  
}, 1000)  

如何你的界面上有按钮,有动画,那么不出意外的,你的动画不懂了,按钮也无法点击了,此时浏览器就出现了假死的情况

为了解释上面的问题,我们来深入解析一下浏览器。浏览器中有三个常驻的线程,分别是JS引擎,界面渲染,事件响应。由于这三个线程同时要访问DOM树,所以为了线程安全,浏览器内部需要做互斥:

当JS引擎在执行代码的时候,界面渲染和事件响应两个线程是被暂停的。所以当JS出现死循环,浏览器无法响应点击,也无法更新界面。现在的浏览器的JS引擎都是单线程的,尽管多线程功能强大,但是线程同步比较复杂,并且危险,稍有不慎就会崩溃死锁。单线程的好处不必考虑线程同步这样的复杂问题,简单而安全

JS引擎基于事件来执行代码。事件响应线程在接到事件后,把响应的代码放到JS引擎的队列中,JS引擎按顺序执行代码。在JS引擎没有代码可以执行的时候,事件线程和渲染线程得以有机会运行,这也就解释了浏览器假死的根本原因,事件线程和渲染线程的执行时机被占用

就像上文中我的描述,setTimeout,setInterval并不是多线程,只是一个定时的事件触发器,它们在合适的时间(时间结束后)把定时器的回调事件塞到JS引擎的队列中。

举个例子,setTimeout(aFunction, 0),这行代码看似的意思是在0秒之后执行aFunction, 但这并不意味着立即执行。其它真正的意思是立刻把aFunction的代码放到当前JS引擎的队列中。所以当前代码块执行完成之前,aFunction的代码是得不到执行的。

比如这段代码,一定是world先出来,hello后出来。尽管setTimeout的参数是0,但这并不意味着立即执行

setTimeout(function() {  
    alert("hello");  
}, 0)  
alert("world")  

就如上文中消息队列说所示图片一样,setTimeout会被计时“线程”接受,然后立即塞入队列中,而在被计时线程接受的过程中,world已经被执行了,hello也侍被塞到了world之后

但是,ajax有有点不一样,为什么没有听到说ajax会 阻塞页面渲染呢?

事实上异步Ajax确实用了多线程,只是Ajax请求的Http连接部分由浏览器另外开了一个线程执行,执行完毕之后给JS引擎发送一个事件,这时候异步请求的回调代码得以执行。它的执行流程是这样的

至此有没有得出什么结论

js确确实实是单线程,但是js通过使用浏览器的多线程实现了异步等操作

其实这就是一个很迷惑的问题,一直说js是单线程,但是学到浏览器的事件循环又一直有计时线程之类的,其实是借助了浏览器的多线程,但是对于js来说,自己还是一个单线程,计时任务分配出去了,但事实回调还是在,例如setTimeout依然只是一个事件调用,在一些大量计算的时候还是会导致死锁 

二,浏览器web worker,真正的多线程

在HTML5中,引入了Web Worker这个概念。它能够在另外一个线程中执行计算密集的JS代码而不引起页面卡死,这是真正的多线程

通过类似定时器,回调函数等异步编程方式在平常的工作中已经足够,但是如果做复杂运算,这种方式的不足就逐渐体现出来,比如settimeout拿到的值并不正确,或者页面有复杂运算的时候很容易触发假死状态,异步代码会影响主线程的代码执行,异步终究还是单线程,不能从根本上解决问题。

多线程(Web Worker)就应运而生,它是HTML5标准的一部分,这一规范定义了一套 API,允许一段JavaScript程序运行在主线程之外的另外一个线程中。将一些任务分配给后者运行。在主线程运行的同时,Worker子线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程就不会被阻塞

1. web worker详解

web worker开发手册icon-default.png?t=N3I4https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers

worker是window对象的一个方法,可以通过以下方式来检测你的浏览器是否支持worker

if (window.Worker) {……}else{alert('不支持web worker')}

创建一个新的 worker 很简单。你需要做的是调用Worker() 的构造器,指定一个脚本的 URI 来执行 worker 线程

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

worker通过postMessage() 方法和onmessage事件进行数据通信。主线程和子线程是双向的,都可以发送和监听事件,举个例子

myWorker.postMessage('hello, world'); // 发送
worker.onmessage = function (event) { // 接收
	console.log('Received message ' + event.data);}

 postMessage所传的数据都是拷贝传递,数据子线程也是类似

当子线程运行结束后,使用完毕,为了节省系统资源,可以手动关闭子线程。如果worker没有监听消息,那么当所有任务执行完毕(包括计数器)后,它就会自动关闭

// 在主线程中关闭
worker.terminate();
// 在子线程里线程
close();

 2. 使用限制

Worker子线程所在的全局对象,与主线程不在同一个上下文环境,所以无法读取 DOM 对象,也无法使用document、window、parent这些对象,global对象的指向有变更,window需要改写成self,当然也不能不能执行alert()方法和confirm()等方法,只能读取部分navigator对象内的数据

分配给Worker 线程运行的脚本文件(worker.js),必须与主线程同源。这里的同源限制包括协议、域名和端口,不支持本地地址(file://)

3.使用场景

Web Worke设计的初衷就是用来做计算耗时任务,大数据的处理,而这种计算放在worker中并不会中断前台用户的操作,避免代浏览器假死。例如处理ajax返回的大批量数据,读取用户上传文件等。worker中除了缺失了DOM和BOM操作能力以外,还是拥有非常强大的js逻辑运算处理的能力的,相当于nodejs一个级别的的运行环境

Vue 3支持Web Worker多线程的特性,这是一种在浏览器中运行JavaScript代码的方式,可以在后台运行独立的线程,提高应用程序性能和响应能力。 在Vue 3中,可以使用`Vue. createApp()`方法创建Vue实例,并使用`createWebWorker`方法将其转换为Web Worker。这个方法接收一个参数,指定Worker脚本的URL或者内联函数的URL。例如: ```javascript const app = Vue.createApp({...}); const worker = app.createWebWorker('path-to-worker-script.js'); ``` 然后,可以使用`worker`对象的方法与Web Worker进行通信。例如,通过`postMessage`方法发送消息给Worker线程: ```javascript worker.postMessage({ data: 'message' }); ``` 同时,还可以通过`onmessage`事件监听来自Worker线程的消息: ```javascript worker.onmessage = function(event) { const data = event.data; // 处理接收到的消息 }; ``` 在Worker线程中,可以使用`self`关键字引用Worker对象,同样可以通过`postMessage`方法发送消息给主线程,并通过`onmessage`事件处理来自主线程的消息。 Web Worker多线程功能可以极大地提高Vue应用程序的性能和响应能力,将一些耗时的操作(如计算、渲染等)放在Worker线程中运行,避免阻塞主线程,提高用户体验。 需要注意的是,在使用Web Worker时,需要考虑到跨域访问的限制,以及数据传输的序列化和反序列化等问题。在实际应用中,需要根据具体需求和场景合理使用Web Worker多线程功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值