• JS学习笔记——在浏览器中处理复杂运算需要注意的问题


      本篇学习笔记内容源于《Secrets of the JavaScript Ninja》

      众所周知,JS在浏览器中是以单线程的方式运行的,因此,JS在异步处理问题时,采用的是排队等候的方式,即当某个JS事件触发时,如果队列里没有其他要执行的JS代码,则该事件立即执行,否则,按照先进先出的方式进入队列等候。

      备注:setInterval()方法具有定义一个按照指定间隔时间连续触发某函数的功能,但在浏览器的JS队列里,只能存储唯一的一个有某个setInterval()方法所产生的触发事件,即如果setInterval()每隔3秒触发执行一个函数,但此时浏览器在5秒钟之内一直被某个应用占用者,那么setInterval()所触发的事件只能有一个进入队列,当第二个进入队列时会被丢弃,如果第一个进入队列的事件执行完毕后,才能再进入下一个。因此setInterval()所触发的事件可能会出现“丢帧”的现象。

      备注可以先不管它,我们接第一段的内容。当浏览器中处理某个复杂运算时,会占用浏览器较长的时间,由于JS的单线程特性,此时如果用户在浏览器上进行一些交互操作,很可能出现“卡”的现象,如果运气不佳,那浏览器会“死”在那里(一些浏览器会监控单线程的执行情况,如果在几秒内一直有某个运算占据着线程不放,浏览器会及时终止正在执行的线程,以腾出资源让队列里的其他事件得以触发执行)

      但有时因为特殊需求,我们需要在浏览器中执行一些复杂操作,例如在一组数量较大的DOM树中进行一些操作。为了避免上述可能出现的浏览器停滞问题,我们需要想一些办法。此时定时器timers也许能帮上忙,是的,它能将一段需要长时间执行的程序,分解成若干小段,并以某一间隔时间依次触发小段程序,最终完成复杂的操作。

    <div>
        <table><tbody></tbody></table>
    </div>
    <script type="text/javascript">
          var tbody = document.getElementsByTagName("tbody")[0];
          for (var i = 0; i < 20000; i++) {
               var tr = document.createElement("tr");
               for (var t = 0; t < 6; t++) {
                   var td = document.createElement("td");
                   td.appendChild(document.createTextNode(i + "," + t));
                   tr.appendChild(td);
               }
               tbody.appendChild(tr);
          }
    </script>

      上面代码中的主要操作会循环执行2000*6=120000次,浏览器至少也得执行5秒钟以上,我的点好执行了大约10秒呵呵,期间什么也干不了,只能等待,这种体验糟透了,所以需要利用timer进行改进,代码如下:

    <script type="text/javascript">
         var rowCount = 20000;                                 
         var divideInto = 10;                                   
         var chunkSize = rowCount/divideInto;                  
         var iteration = 0;                                    
         var table = document.getElementsByTagName("tbody")[0];
         setTimeout(function generateRows(){
                var base = (chunkSize) * iteration;                
                for (var i = 0; i < chunkSize; i++) {
                     var tr = document.createElement("tr");
                     for (var t = 0; t < 6; t++) {
                         var td = document.createElement("td");
                         td.appendChild(
                              document.createTextNode((i + base) + "," + t +
                                                       "," + iteration));
                         tr.appendChild(td);
                     }
                     table.appendChild(tr);
                }
                iteration++;
                if (iteration < divideInto)
                    setTimeout(generateRows, 50);
          }, 0);
    </script>

      上面的代码并不难懂,在开始设置了一些变量,用来把大循环分解成的若干个(10个)小循环,每次小循环执行后,再间隔50ms调用generateRows()函数,这样浏览器虽然反应迟钝,但还在不会死掉了。

      

  • 相关阅读:
    sls异常日志钉钉告警
    vue3.0学习
    docker安装mysql5.7
    封装quarz,实现自己的job集群
    封装hangfire,实现自己的job集群
    ts+vue3学习
    cellreport集成iis
    ocelot网关设置
    asp.net core 跨域
    高性能的MQBUS
  • 原文地址:https://www.cnblogs.com/bingbing/p/2915917.html
Copyright © 2020-2023  润新知