众所周知,JS 的一大特点就是单线程,也就是说在同一时间只能执行一件事情。那为什么不像 JAVA 等语言一样,为了提高效率设置为多线程的呢?
  这主要与 JS 的用途有关,JS 是浏览器脚本语言,主要用途是实现浏览器与用户的交互、以及对 DOM 元素的操作。这一用途决定了 JS 只能是单线程的,否则会造成一些复杂的同步问题。
  我们来设想一下如果 JS 是多线程,会发生怎样的现象。所谓多线程,简单来说就是同一时间进行多项操作,如果 JS 设计成多线程,多个线程同时操作同一 DOM 元素,比如一个线程在修改该 DOM 元素,而与此同时另一线程在执行删除该 DOM 元素的操作,这种情况下浏览器就不知道到底应该执行哪种操作,所以就产生的复杂的同步问题。
  所以说,JS 注定只能是单线程的,这一点已经成为了该语言的一个核心特征,不会发生改变。

  那为了更好的利用 CPU 提高效率,HTML5 提出 Web Worker 标准,允许 JS 创建多个线程,我们借助 Worker 类,可以向浏览器申请一个新的线程作为子线程,该线程可以用来单独执行一个 JS 文件。

let worker = new Worker(js文件路径);  // Worker 线程无法读取本地文件,该文件路径只能为网络资源

  Worker 子线程的限制:
    1) 分配给子线程的 JS 文件必须与主线程 JS 文件同源;
    2) 子线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也就是子线程无法进行 DOM 操作,也无法使用document、window、parent这些对象。但是,子线程可以navigator对象和location对象。
    3) 子线程无法调用 alert() 、 confirm() 方法,可以使用 XMLHttpRequest 对象发送 AJAX 请求;
    4) Worker 线程无法读取本地文件,子线程加载的脚本文件路径只能为网络资源

  主线程通过 worker.postMessage() 方法向子线程发送数据(可以是任何类型的数据),通过 worker.onmessage 指定监听函数,接收子线程发回的数据。子线程完成任务后主线程应该调用 worker.terminate(); 关闭子线程。
  子线程可以通过监听 message 事件获取主线程发过来的数据,通过 self.postMessage() 方法向主线程发送数据, self 代表子线程全局对象

主线程:
    // 向浏览器申请一个子线程
    let worker = new Worker('http://localhost:8080/test/js/worker.js', {
        name: 'firstWorker'
    });
    // 向子线程发送数据
    worker.postMessage('你好,子线程,请开始工作。。。');    				    
    // 监听 message 事件,监听子线程发送的数据
    worker.onmessage = (event) => {
        console.log('接收到子线程发来的数据:【 ' + event.data + ' 】');
	// 关闭子线程
	worker.terminate();
    }
			
子线程:
    console.log('子线程名称:' + self.name);
    // 监听主线程发来的数据
    self.addEventListener('message', (e) => {
        console.log('接收到主线程发送的数据:【 ' + e.data + ' 】');
    })
    setTimeout(() => {
	// 5s后向主线程发送一条数据
	self.postMessage('主线程你好,我来自子线程');
	// 子线程关闭自身
	self.close();
    }, 5000)                        

  如果子线程内部需要加载其他 JS 脚本文件,可以使用 importScripts() 方法,如: importScripts('script1.js', 'script2.js');
  如果子线程发生错误,会触发主线程的 error 事件,主线程可以通过监听 error 事件进行处理:
  

worker.onerror(function (event) {
    console.log([
        'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
    ].join(''));
});    


第一次写博客,如有错误,烦请指正,如有侵权,请联系删除~
参考文献:http://www.ruanyifeng.com/blog/2018/07/web-worker.html

 

转载请注明出处: https://www.cnblogs.com/yLiu1006/p/13619007.html

posted on 2020-09-05 17:54  取名向来是件难事  阅读(1037)  评论(0编辑  收藏  举报