• 使用多线程Worker解决切换页面定时器停止


    worker介绍

    worker是独立于web主线程的,在后台运行的线程。

    web worker的优点就是可以将工作交给独立的其他线程去做,这样就不会阻塞主线程。

    浏览器端js是单线程执行,所以当js执行高负载运算时,UI渲染就会阻塞,页面就会出现卡顿,用户体验就不是很好.

    js为此也提供了异步操作,例如: 定时器(setTimeout 和 setInterval),Ajax请求等,但异步终究还是单线程,不能从根本上解决问题,像setTimeout并不能拿到正确的值,因为执行的时候将该任务放到主线程执行,只有当前面的任务执行完才开始执行,所以即使设置时间为0,也并不一定立刻执行.

    所以HTML5标准添加了Web Worker,worker允许一段js程序运行在主线程之外的线程,子线程与主线程互不干扰,当子线程的代码执行完成,将结果返回给主线程,主线程接收到相应结果后再做对应处理,当有一些计算密集型或高延迟的任务就可以交给worker子线程来负担,主线程就不会阻塞.

    worker使用

    worker是window对象的一个方法,一个worker对象可通过构造函数(window.worker())来创建,创建对象时,需要传给构造函数一个js文件,该文件包含了放到子线程中运行的代码。

    worker通过postMessage()和onmessage = () => {} 来进行通信,主线程和子线程通信是双向的,都有可以发送和接收信息,postMessage传递的数据都是拷贝传递(ArrayBuffer除外)

    子线程运行耗损系统资源,所以当执行完毕后,我们可以手动关闭子线程

             在主线程中关闭: worker.terminate()

             在子线程中关闭: self.close()  (在子线程中window需改写成self,下文有解释)

    worker限制

         1)同源

            分配给worker子线程运行的脚本文件,必须与主线程的脚本文件同源,包括协议,域名和端口,不支持本地地址(file://);

            当使用CDN来存储js文件时,主线程与子线程就会出现跨域

            解决方法: 【1】将子线程的脚本转换成Blod对象

                            【2】然后给Blod对象创建一个URL

                            【3】将这个URL传给worker的构造函数

           示例代码: 

              var workerBlob = new Blob(['(' + function +')()'], { type: "text/javascript" });

              var url = window.URL.createObjectURL(workerBlob);

              var worker = new Worker(url);

        2) 访问 

            worker子线程所在的全局对象,与主线程不在一个上下文环境,所以无法读取主线程所在网页的DOM,无法使用document,window,parent这些对象,global指向有变更,window需要改写成self,不能执行alert()和comfire()的方法,只能读取部分navigator对象内的数据

       3)使用异步

            worker子线程中支持js的异步操作,但仍然不可以跨域

        worker的兼容性还不错,但不兼容IE9

    以上内容参考:https://www.cnblogs.com/yezi-dream/p/10202593.html

    案例:worker解决谷歌浏览器切换页面定时器停止

    浏览器为了性能考虑,在你切换完选项卡之后会清除掉这里的缓存数据,这样会导致切换页面定时器会停止,比如:如果做一个在线考试系统,如果用户切换浏览器计时停止就达不到控制时间的目的。

    1. html>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. head>
    6. <body>
    7. 计时器<span id="countNum">0span>
    8. <script type="text/javascript">
    9. var countEle = document.getElementById("countNum");
    10. var i = 0;
    11. setInterval(function(){
    12. i++;
    13. countEle.innerText = i;
    14. },1000);
    15. script>
    16. body>
    17. html>

    打开谷歌浏览器,切出当前页面,过几分钟后再看,可以发现时间有延迟和停止现象。

    解决:worker多线程

    1. html>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. head>
    6. <body>
    7. 计时器<span id="countNum">0span>
    8. <script type="text/javascript">
    9. var countEle = document.getElementById("countNum");
    10. var i = 0;
    11. //setInterval(function(){
    12. // i++;
    13. // countEle.innerText = i;
    14. //},1000);
    15. var blob = new Blob(['(function(e){setInterval(function(){this.postMessage(null)},1000)})()']);
    16. var url = window.URL.createObjectURL(blob);
    17. var work = new Worker(url)
    18. work.onmessage = function(e){
    19. i++;
    20. countEle.innerText = i;
    21. if(i == 60)
    22. {
    23. work.terminate();
    24. }
    25. }
    26. script>
    27. body>
    28. html>

  • 相关阅读:
    Scratch 画画的技巧
    最新科技喜报!统一图像和文字生成的MiniGPT-5来了!
    Vue 之 Toast 消息提示插件的简单封装
    Linux批量注释
    Spring Boot中Node.js的下载与Vue CLI在IDEA中的部署及使用(图文解释 简单易懂)
    Claude 2,它有 GPT-4 一些无法超越的能力
    ubuntu18.04服务器双网口配置上外网
    鸿蒙HarmonyOS实战-ArkUI组件(Canvas)
    Python学习之CSDN21天学习挑战赛计划之4
    python3 简易 http server:实现本地与远程服务器传大文件
  • 原文地址:https://blog.csdn.net/amyliyanice/article/details/126358842