一.为什么JavaScript是单线程?
JavaScript是单线程语言,即同一时间只能做一件事(同步)
JavaScript主要用途是用户交互即操作DOM,决定了其只能是单线程,比如说,在一个DOM添加新的内容,并删除这个元素,如果是多线程,那应该先操作哪步,必然会矛盾,单线程则不会,按先后顺序执行
二. 任务队列(异步)
单线程意味着所有的任务都要排队进行,如果碰到耗时长的操作(IO设备,定时器。。),会造成js阻塞,形成页面假死状态,所有采用异步执行:
- 所有的同步任务都会在主线程上执行,形成执行栈
- 主线程之外,存在一个"任务队列"(task queue),将异步任务的事件放到任务队列中
- 执行栈中所有的同步任务执行完毕后, 开始读取任务队列,将任务队列中的事件放到执行栈中执行(先进先出)
- 重复执行上面三步,这就是js event-loop(事件循环)
web worker 实现多线程
worker 是 H5中引入的实现多线程的方案
先检测你的浏览器是否支持worker
if( window.worker ) { ...code }
实现代码
// main.js 主代码
var worker = new Worker('worker.js') //创建并实例化个对象
worker.postMessage(36) // 发送数据
// 接受返回的数据
worker.onmessage = function(event){
var data = event.data; // 返回的数据
}
// 报错处理
worker.onerror = function(event){
console.log(event.filename,event.lineno,evnet.message)
}
worker.terminate() // 自动关闭
// worker.js
// 子线程中不能再调用 new Worker创建新的子线程
// 接收数据
self.onmessage = function(event){
var data = event.data; // 此处就是从 main.js 传过来的 36
。。。逻辑处理
postMessage(newData) // 发送新的数据到 main.js
}
self.close() // 子线程中手动关闭
使用的限制
- 同源限制
分配给Worker 线程运行的脚本文件(worker.js),必须与主线程的脚本文件(main.js)同源 - 访问限制
Worker子线程所在的全局对象,与主线程不在同一个上下文环境,无法读取主线程所在网页的 DOM 对象, 也无法使用document、window、parent这些对象,global对象的指向有变更,window需要改写成self,不能执行alert()方法和confirm()等方法,只能读取部分navigator对象内的数据。另外chrome的console.log()倒是可以使用,也支持debugger断点,增加调试的便利性。 - 使用异步
Worker子线程中可以使用XMLHttpRequest 对象发出 AJAX 请求,可以使用setTimeout() setInterval()方法,也可使用websocket进行持续链接。也可以通过importScripts(url)加载另外的脚本文件,但是仍然不能跨域。
应用场景
1、使用专用线程进行数学运算
2、高频的用户交互
3、数据的预取
参考文献
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
https://juejin.im/post/5bcc1887f265da0aff177227#comment
网友评论