web worker实际使用

web worker的好处

相信大家都比较熟悉,比如:

  • 为js创造多线程环境,一些 计算量大的 耗时的 任务,可以用web worker单独开线程去跑,不会影响到主线程的运行
    • 这样主线程(ui交互渲染等)就不会被阻塞,页面流畅

实际如何使用呢?

首先要理解一个区别,主线程和子线程是分别独立,不要混在一起去理解
web worker.png

上一段代码,方便理解:

  1. // 文件的目录结构:
  2. ├── index.html
  3. └── poorWorker.js (穷人打工仔,worker,干活的人)

这是主线程:index.html

  1. <script>
  2. const worker = new Worker('./poorWorker.js');
  3. worker.postMessage("我是主进程, 我是boss,我传给worker线程消息: 赶紧干活!!");
  4. worker.onmessage = msg => {
  5. console.log(msg)
  6. console.log("我是主进程,我是boss,接收的子线程的数据:", msg.data);
  7. worker.terminate(); // 关闭主线程
  8. };
  9. worker.onerror = e => {
  10. console.log(e)
  11. };
  12. </script>

这是子线程:poorWorker.js

  1. // importScripts('./hello2.js', 'http://xxx/a.js'); // 此处可以指出多脚本, 加载的脚本不支持跨域!!
  2. // self 代表子线程自身,即子线程的全局对象。
  3. // self可以换成this或不写,也可以实现执行。此处用self用于区分子线程worker
  4. // 监听主线程传过来的信息
  5. self.onmessage = e => {
  6. console.log(e)
  7. console.log('我是子线程, 我在工作, 我是worker, 我收到主线程传来的信息:', e.data)
  8. // do something
  9. }
  10. // setTimeout非必须,此处模拟,worker干了个耗时的活,2s后告诉主线程(老板)活已经干完ok了。
  11. setTimeout(() => {
  12. // 发送信息给主线程
  13. self.postMessage('我是子线程, 我在工作, 我是worker, 工作已经完成 ok')
  14. closeSon()
  15. }, 2000)
  16. // 关闭worker线程
  17. function closeSon () {
  18. return self.close()
  19. }

打印效果如下:

webWorkerLog.png

骚操作写法介绍(更推荐上面的写法)

正常情况,推荐上面的写法:把worker部分,单独分离成一个.js文件。

但强行把worker部分,不分离成.js,强行写在index.html内,也可以做到

这是 index.html

  1. <script>
  2. // 此处把上面的poorWorker.js放到data中
  3. const data = `
  4. // importScripts('./hello2.js', 'http://xxx/a.js'); // 此处可以指出多脚本, 加载的脚本不支持跨域!!
  5. // self 代表子线程自身,即子线程的全局对象。
  6. // self可以换成this或不写,也可以实现执行。此处用self用于区分子线程worker
  7. // 监听主线程传过来的信息
  8. self.onmessage = e => {
  9. console.log(e)
  10. console.log('我是子线程, 我在工作, 我是worker, 我收到主线程传来的信息:', e.data)
  11. // do something
  12. }
  13. // setTimeout非必须,此处模拟,worker干了个耗时的活,2s后告诉主线程(老板)活已经干完ok了。
  14. setTimeout(() => {
  15. // 发送信息给主线程
  16. self.postMessage('我是子线程, 我在工作, 我是worker, 工作已经完成 ok')
  17. closeSon()
  18. }, 2000)
  19. // 关闭worker线程
  20. function closeSon () {
  21. return self.close()
  22. }
  23. `;
  24. const blob = new Blob([data]); // 把poorWorker.js的内容转成二进制
  25. const url = window.URL.createObjectURL(blob); // 把二进制转成一个本地链接
  26. const worker = new Worker(url); // 利用了new Worker()只接受url的特点
  27. // ... 后面的代码同上
  28. worker.postMessage("我是主进程, 我是boss,我传给worker线程消息: 赶紧干活!!");
  29. worker.onmessage = msg => {
  30. console.log(msg)
  31. console.log("我是主进程,我是boss,接收的子线程的数据:", msg.data);
  32. worker.terminate(); // 关闭主线程
  33. };
  34. worker.onerror = e => {
  35. console.log(e)
  36. };
  37. </script>

最后(断开)

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。

但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。


码字不易,点赞鼓励