息壤

导航

 

  本篇学习笔记内容源于《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()函数,这样浏览器虽然反应迟钝,但还在不会死掉了。

  

 

posted on 2013-02-19 18:00  息壤  阅读(437)  评论(0编辑  收藏  举报