定時器學習:利用定時器分解耗時任務案例

對於執行時間過長的腳本,有的瀏覽器會彈出警告,說頁面無響應。有的瀏覽器會直接終止腳本。總而言之,瀏覽器不但願某一個代碼塊長時間處於運行狀態,由於js是單線程的。一個代碼塊長時間運行,將會致使其餘任何任務都必須等待。從用戶體驗上來講,頗有可能發生頁面渲染卡頓或者點擊事件無響應的狀態。javascript

若是一段腳本的運行時間超過5秒,有些瀏覽器(好比Firefox和Opera)將彈出一個對話框警告用戶該腳本「沒法響應」。而其餘瀏覽器,好比iPhone上的瀏覽器,將默認終止運行時間超過5秒鐘的腳本。--《JavaScript忍者祕籍》

JavaScript忍者祕籍裏有個很好的比喻:頁面上發生的各類事情就好像一羣人在討論事情,若是有我的一直在說個不停,其餘人確定不樂意。咱們但願有個裁判,定時的切換其餘人來講話。html

Js利用定時器來分解任務,關鍵點有兩個。java

  1. 按什麼維度去分解任務
  2. 任務的現場保存與現場恢復

例子

要求:動態建立一個表格,一共10000行,每行10個單元格瀏覽器

一次性建立

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

<table>
    <tbody></tbody>
</table>

<script type="text/javascript">
    var tbody = document.getElementsByTagName('tbody')[0];

    var allLines = 10000;
    // 每次渲染的行數

    console.time('wd');
    for(var i=0; i<allLines; i++){
        var tr = document.createElement('tr');

        for(var j=0; j<10; j++){
            var td = document.createElement('td');

            td.appendChild(document.createTextNode(i+','+j));
            tr.appendChild(td);
        }

        tbody.appendChild(tr);
    }
    console.timeEnd('wd');

</script>
</body>
</html>

總共耗時180ms, 瀏覽器已經給出警告![Violation] 'setTimeout' handler took 53msapp

圖片描述

分批次動態建立

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

<table>
    <tbody></tbody>
</table>

<script type="text/javascript">
    var tbody = document.getElementsByTagName('tbody')[0];

    var allLines = 10000;
    // 每次渲染的行數
    var everyTimeCreateLines = 80;
    // 當前行
    var currentLine = 0;

    setTimeout(function renderTable(){
        console.time('wd');
        for(var i=currentLine; i<currentLine+everyTimeCreateLines && i<allLines; i++){
            var tr = document.createElement('tr');

            for(var j=0; j<10; j++){
                var td = document.createElement('td');

                td.appendChild(document.createTextNode(i+','+j));
                tr.appendChild(td);
            }

            tbody.appendChild(tr);
        }
        console.timeEnd('wd');

        currentLine = i;

        if(currentLine < allLines){
            setTimeout(renderTable,0);
        }
    },0);

</script>
</body>
</html>

此次異步按批次建立,沒有耗時的警告。由於控制了每次代碼在50ms內運行。實際上每80行耗時約10ms左右。這就不會引發頁面卡頓等問題。異步

圖片描述

相關文章
相關標籤/搜索