这是我参与更文挑战的第17天,活动详情查看:更文挑战
[重学JavaScript系列文章连载中...]
我们都知道JavaScript是单线程的,只有等上个任务执行完,才能执行下一个任务。当执行一些密集型或者高延迟的任务时,会造成主线程的阻塞,浏览器页面冻结。Web Worke的出现,为JavaScript创造多线程环境。允许主线程创建Worker线程,并将任务分配给worker线程。并且Worker线程是在后台运行,与主线程互不干扰。所以可以将耗时、密集型任务分配给Worker线程,等执行完成再通知主线程。
看看使用Web Worker的简单例子:
// 主线程 index.js
// 传入一个要执行的js文件,实例化Web Worker
// 此时会导致浏览器下载js文件,但不会执行
let worker = new Worker('worderDemo.js')
// 监听Worker传递过来的信息
worker.onmessage = function(event){
const {data} = event
}
// 监听Worker内部错误
worker.onerror = function(event){
const {
filename, // 文件名
lineno, // 代码行数
message // 完整的错误信息
} = event
}
// 给Worker发送消息启动执行
worker.postMessage({
type:'cmd',
data:'start'
})
// 停止worker的工作,内部代码会立即停止执行,后续的过程都不会再发生
worker.terminate()
// Web Worker: worderDemo.js
// 监听主线程的发送消息
self.onmessage = function(event){
const {data} = event
self.postMessage({
type:'end',
data:'Worker处理完数据了'
})
}
这个例子里的Worker只能为指定的页面服务,不能在页面共享的,因此也称为“专用Worker”。关于页面共享的“Worker”目前尚未有完成规范。
代码里为啥用self进行监听呢?这里看看Worker的作用域。
Worker所执行的JavaScript是完全独立的一个作用域,不与页面共享作用域,且Web Worker中的全局对象指向的是worker对象本身,所以this指向worker对象,这里self也引用worker对象。在这个特殊域中,无法访问DOM,也无法通过任何形式影响页面的外观。
当然,Web Worker本身也是一个最小化的运行环境,不过跟页面环境是没法比。存在以下可操作对象:
- 最小化的navigator对象,包括onLine、appName、appVersion、userAgent和platform属性
- 只读的location对象
- setTimeout()、setInterval()、clearTimeout()和clearInterval()方法
- XMLHTTPRequest构造函数
最后总结下几个注意点:
- 同源策略:分配给Worker线程运行的脚本文件,必须与主线程的脚本文件同源
- 脚本限制:不能执行alert()和confirm()方法,但可以使用XMLHTTPRequest
- 文件限制:Worker无法读取本地文件(file://),所加载的文件必须来源网络
- DOM限制:Worker不能操作Dom,也无法使用window/doument这些,但可以使用navigator等。
- 通信联系:Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
至此,简单学习了下Web Workers应用。