Web Worker 和 Server-Sent Events

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web Worker 和 Server-Sent Events相关的知识,希望对你有一定的参考价值。

参考技术A

js 是单线程执行,但是不能重复利用现在多核 CPU的特性。web worker在后台运行,主线程和web worker互不干扰。可以把一些计算密集的任务交给web worker,这样浏览器就会一直很顺畅。

必须要注意web worker的同源限制、DOM限制、通信限制、脚本限制等。web worker 不能让你操作dom,主要用来做一些计算密集,IO密集操作(输入输出,像磁盘存取数据)
web worker的详细用法——阮一峰

Server-Sent Events简称sse,sse的主要作用是方便服务端向客户端推送信息。
轮询、长轮询、sse、WebSocket 区别。
轮询: 就是不停 的请求,有新数据就更新,没有就为空

长轮询: 就是服务端延迟回复,有新消息才回复,没有就不会。

sse: 就是客户端与服务端建立连接之后,服务端可以随时给客户端推送消息,而且sse使用的是http协议,比较轻量级,默认支持断线重连。sse相当于的 单向 推送 ,客户端不能给服务端发消息。

WebSocket: WebSocket属于 全双工 ,可以双方推送消息。

Server-Sent Events详细用法——阮一峰

HTML5( Web Worker ) & 微信小程序多线程

随着互联网的发展,技术也在不断的更新,2014年10月29日万维网联盟发布HTML5语言标准,HTML5推出了很多API例如Geolocation(地理定位)Storage(本地存储)Cache Manifest(应用程序缓存)Server-Sent(自动获取来自服务器的更新)WebSocket(及时通讯)indexedDB(本地数据库),还有一个就是接下来要说的Web Worker(多线程)

学习JavaScript的人都知道JavaScript语言不如javaC#等,其他强类型语言使用的是多线程处理程序,JavaScript使用单线程处理程序。

JavaScript为什么不适用多线程

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

进行&线程

进程

进程是指在操作系统中正在运行的一个应用程序

线程

线程是指进程内独立执行某个任务的一个单元。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)。

什么是Web Worker

web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。

一般来说Javascript和页面的UI会共用一个线程,所以当点击一个按钮开始运行Javascript后,在这段代码运行完毕之前,页面是无法响应用户操作的,换句话来说就是被“冻结”了,即使是异步的也会被冻结。如下面这段代码。

window.onload = () => {
   alert(1)
   setInterval(() => {
       console.log(1)
   },500)
}

上面这段代码在页面加载完成以后,先执行alert然而,alert页面进入了无法相应的状态,换句话来说,下面的代码就被冻结了,只有把alert确定以后才会执行下面的定时器。

而这段代码可以交给Web Worker在后台运行,那么页面在Javascript运行期间依然可以响应用户操作。后台会启动一个worker线程来执行这段代码,用户可以创建多个worker线程。

Web Worker提供了什么

  1. 加载一个JavaScript文件,进行大量的复杂计算,而不挂起主进程,并通过postMessageonMessage进行通信。

  2. 可以再Worker中通过importScript()方法加载JavaScrip脚本

  3. 可以使用setTimeOut()setInterVal()clearTimeout()clearInterVal()等。

  4. 可以使用XMLHttpRequest进行请求。

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

  6. 可以使用JavaScript核心对象

Web Worker限制

  1. 不能跨域加载JavaScript文件。

  2. Worker内代码不能访问DOM。

  3. 各个浏览器对Worker的实现还没有完全完善,不是每个浏览器都能支持这一新特性。

  4. 使用Web Workers加载数据没有JSONAjax加载数据高效。

Web Worker主要成员

在使用Web Worker之前,应该先熟悉一下线程中可用的变量,函数和类。在线程中调用JavaScript函数中的所有,可使用类和函数如下:

  1. self:self关键值用来表示本线程范围内的作用域。

  2. postMessage:向创建线程的原窗口发送消息。

  3. navigator:与window.navigator对象类似,具有appNameplatformuserAgentappVersion属性。他们可以用来识别浏览器的标识符。

  4. sessionStorage/localStorage:在线程中可以使用web Storage

  5. XMLHttpRequest:在线程中可以处理Ajax请求。

  6. setTimeOut/setInterVal:在线程中可以实现定时处理。

  7. close:结束本线程。

  8. eval()/isNaN/escape()等:可以使用所有JavaScript核心函数。

  9. object:可以创建和使用本地对象。

  10. WebSockets:可以使用Web Sockets API向服务器发送和接收消息。

浏览器兼容性

浏览器 说明
IE 不支持
firefox 3.5以及以上的版本
Opera 10.6及以上的版本
Chrome 3.0及以上的版本
Safari 4.0及以上的版本
# 兼容性检测
let isWorker = () => {
   let flag = false;
   if(typeof(Worker)!=="undefined"){
       flag =  true;
   }
   return flag;
}

Web Worker简单应用

简单看一下代码是怎么实现的。需要注意的是一定要在服务器环境下才能正常使用Web Worker。

index.html

<html>  
 <head>  
 <script type="text/javascript">  
   var worker = new Worker('worker.js');  
   var obj = {"first":1, "second":2};  
   worker.postMessage(obj);  
   worker.onmessage = function (event) {  
     console.log(event.data);  
   }  
   function postMsg(){  
     if (worker)  
       worker.postMessaage(obj);  
   }  
 
</script>  
 </head>  
 <body>  
    <button onclick="postMsg()">post</button>  
 </body>  
</html>  

worker.js

onmessage = function (event)   
{  
 var data = event.data;  
 var first=data.first;  
 var second=data.second;  
 handleTask(first,second);  
};  
function  handleTask(a, b)  
{  
  var out = a + b;  
  postMessage("Worker Done! out = " + out);  
}  

运行代码:点击查看案例

Web Worker运行流程

  1. 执行到"var worker = new Worker('worker.js')“时,在内核中构造WebCore::JSWorker对象(JSBbindings层)以及对应的WebCore::Worker对象(WebCore模块);

  2. 执行worker.postMessage(),向worker线程发送JSON格式化的消息数据; 因为这个时候,worker线程还没有创建,所以消息数据放在一个临时消息队列中;

  3. worker.js异步加载完成后,创建并启动worker线程,并将临时消息队列中的消息数据copy到woker对应的WorkerRunLoop的消息队列中;

  4. worker线程创建完成后,开始处理WorkerRunLoop的消息队列中所保存的消息;

  5. woker线程发送消息到主线程;

  6. 主线程收到worker线程发送的消息,执行onMessage();

Web Worker案例

生成200个100以内随机数,筛选出能被3整除的,并展示到页面。

index.html

let $ = (id) => {
   return document.getElementById(id);
}
window.onload = () => {
   let arr = [];
   for(let i=0;i<200;i++){
       arr.push(Number.parseInt(Math.random()*100));
   }
   let worker = new Worker("/www/worker/worker2.js");
   worker.postMessage(JSON.stringify(arr));
   worker.onerror = (err) => {
       console.log(err);
   }
   worker.onmessage = (event) => {
       let arr = event.data;
       arr.map((el,i) => {
           let li = document.createElement("li");
           li.innerHTML = el;
           $("ul").appendChild(li);
       })
   }
}

worker.js

onmessage = (event) => {
   let arr = JSON.parse(event.data);
   let a = arr.filter((el,i) => {
       return el%3 === 0;
   })
   postMessage(a);  
}

运行代码:点击查看案例

共享线程

共享线程是为了避免线程的重复创建和销毁过程,降低了系统性能的消耗,共享线程SharedWorker可以同时有多个页面的线程链接。

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

共享线程也使用了message事件监听线程消息,但使用SharedWorker对象的port属性与线程通信如下。

worker.port.onmessage = function(e){
   ...
}

同时我们也可以使用SharedWorker对象的port属性向共享线程发送消息如下。

worker.port.postMessage("message");

小结

在写这篇文章之前看了很多博客,同样也看了 ++HTML5+CSS3从入门到精通++ 这本书,很多博客都说可以进行线程嵌套,一定要记住,是不能进行线程嵌套的,就是在 worker.js 文件里面再次 new Worker 这样的话会报错。原因是Worker对象属于window,所以在线程文件中使用Worker对象会抛出错误Worker is not defined

Web Worker可以在后台完成复杂的数据计算。这是其最有利的地方。所以一定要合理的使用这一特点。不是任何时候都适用Web Worker,否则会有些小题大做,给维护带来没有必要的麻烦。

微信小程序多线程

创建一个 Worker 线程,并返回 Worker 实例,目前限制最多只能创建一个 Worker,创建下一个 Worker 前请调用 Worker.terminate

微信小程序的多线程和H5多线程是类似的,唯一的区别就是,小程序多线程处理无需服务器环境即可运行了。

scriptPath 为 worker 的入口文件路径,需填写绝对路径。

app.js

const worker = wx.createWorker('workers/request/index.js');
worker.postMessage({
 msg: 'hello worker'
})
worker.onMessage(function (res) {
 console.log(res)
})
worker.terminate

worker.js

worker.onMessage(function (res) {
 console.log(res.msg)
})
worker.postMessage("线程返回的数据")

总结

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

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

HTML5 Web Worker 需要服务器环境才能正常使用,使用线程文件和worker文件必须在同一个域下面。否则无法运行。

这个很重要。


--- End ---





 GitHub项目,喜欢的小伙伴Start一下吧:
v-scroller :基于VUE开发的一个移动端滚动插件,作者:alan chen.其功能非常强大,支持上拉加载,下拉刷新。滚动层嵌套。支持npm下载。欢迎小伙伴start支持一波。飞机票:https://github.com/alanchenchen/v-scroller



邦邦堂

前端邦邦堂是一群初入IT编程的人共同组成。用意是互帮互助,共同成长。加入邦邦堂学习群请关注[前端邦邦堂]公众号回复“加群”。投稿请发邮箱到bbt_hello@163.com 


以上是关于Web Worker 和 Server-Sent Events的主要内容,如果未能解决你的问题,请参考以下文章

Server-sent events(SSE)& EventSource 客户端使用与服务器基础实现(基于Node.js)

server-sent event后台用.net怎样实现

WebFlux系列 Server-Sent Events

Server-sent Events

php [cakephp:API组件和控制器]用于ajax请求和Server-Sent事件的Cake模块。 #cakephp

Comet 现在是不是已经过时了 Server-Sent Events 和 WebSocket? [关闭]