6、馴服線程和定時器

定時器和線程是如何工作的

JavaScript提供了兩種方式,用于創(chuàng)建定時器以及兩個相應(yīng)的清除方法。這些方法都是window對象上的。

// 在一段時間(delay)之后執(zhí)行傳入的fn方法,并返回該定時器的唯一標(biāo)識
id=setTimeout(fn,delay);
// 在定時器還未觸發(fā)時,取消定時器
clearTimeout(id)

// 在每間隔一段時間(delay)之后都執(zhí)行傳入的fn方法,并返回該定時器的唯一標(biāo)識
id=setInterval(fn,delay);
// 取消間隔定時器
id=clearInterval(id)

由于JavaScript是單線程的,在特定的時間點只能運行一個執(zhí)行代碼,而且也無法確定定時器處理程序到底是在什么時候執(zhí)行,當(dāng)一個異步事件發(fā)生時(鼠標(biāo)單擊,定時器觸發(fā),或者是ajax返回函數(shù)),它會進行排隊,在線程空閑時才進行執(zhí)行,并且每個瀏覽器的排隊機制是不同的,瀏覽器不會對來自同一個setInterval()的多個回調(diào)進行排隊,同一時刻,將只會有一個來自同一setInterval()的回調(diào)在隊列中。
interval間隔定時器并不是周期執(zhí)行的timeout定時器,通過下面代碼可以看出差異。

setTimeout(function repeat() {
    /*主內(nèi)容代碼*/
    setTimeout(repeat,10);
},10);

setInterval(function () {
    /*主內(nèi)容代碼*/
},10);

在setTimeout()代碼中,要在前一個主題內(nèi)容代碼執(zhí)行結(jié)束并延遲10ms的時間后,才能再次執(zhí)行setTimeout()。
而setInterval()代碼中,每間隔10ms就嘗試執(zhí)行主內(nèi)容代碼,并不會關(guān)注上一次setInterval()中的主內(nèi)容代碼是如何執(zhí)行的。
瀏覽器無法保證我們制定的延遲間隔,尤其是在間隔時間非常小的情況下,因為執(zhí)行回調(diào)函數(shù)和代碼本身也要花費時間。

處理昂貴的計算過程

下面代碼會創(chuàng)建240000個DOM節(jié)點,并使用大量單元格來填充一個表格。

var tbody = document.getElementsByTagName("tbody")[0];
for(var i=0;i<20000;i++){
    var tr = document.createElement("tr");
    for(var j=0;j<6;j++){
        var td = document.createElement("td");
        td.appendChild(document.createTextNode(i+","+j));
        tr.appendChild(td);
    }
    tbody.appendChild(tr);
}

執(zhí)行類似上述計算昂貴的代碼,瀏覽器往往會卡頓很長時間,將這些操作分隔,定期讓代碼中斷,并記錄中斷的地方,間隔一定時間再調(diào)度下一階段。

var row = 20000;
var divede = 10;  // 分隔的數(shù)量
var cur = row / divede;  // 每次執(zhí)行的次數(shù)
var now = 0;  // 執(zhí)行的階段
var tbody = document.getElementsByTagName("tbody")[0];
setTimeout(function goNow() {
    var go = cur * now;  // 記錄上次中斷結(jié)束的地方
    for(var i=0;i<cur;i++){
        var tr = document.createElement("tr");
        for(var j=0;j<6;j++){
            var td = document.createElement("td");
            td.appendChild(document.createTextNode((i+go)+","+j+","+now));
            tr.appendChild(td);
        }
        tbody.appendChild(tr);
    }
    now++; // 調(diào)度下一階段
    if(now<divede){
        setTimeout(goNow,0);
    }
},0);

中央定時器控制

var timers = {  // 定義中央定時器控制對象
    timerID:0,  // 當(dāng)前正在執(zhí)行的定時器,為0則表示沒有定時器在執(zhí)行
    timers: [],  // 保存定時器需要執(zhí)行的所有回調(diào)函數(shù)
    add:function (fn) {  // 定義add方法,添加回調(diào)函數(shù)
        this.timers.push(fn);
    },
    start:function (time) {  // 執(zhí)行定時器
        if(this.timerID) return;  // 沒有定時器時,執(zhí)行一個即時函數(shù)來開啟中央定時器
        (function runNext() {  // 執(zhí)行當(dāng)前定時器
            if(timers.timers.length>0){  // 遍歷所有回調(diào)函數(shù)進行執(zhí)行
                for(var i=0;i<timers.timers.length;i++){
                    if(timers.timers[i]()===false){  // 當(dāng)某個回調(diào)函數(shù)不需要在執(zhí)行時,將其刪除
                        timers.timers.splice(i,1);
                        i--;
                    }
                }
                timers.timerID = setTimeout(runNext,time); // 等待time時間再次調(diào)用定時器
            }
        })();
    },
    stop:function () {  // 清除定時器
        clearTimeout(this.timerID);
        this.timerID =0;
    }
};

// 測試中央控制器
var box = document.getElementById("box"),x=0,y=0;
timers.add(function () {
    box.style.left=x+"px";
    if((x+=1)>200)return false;
});
timers.add(function () {
    box.style.top=y+"px";
    if((y+=1)>200)return false;
});
timers.start(10);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 9.26-9.30 第8章 馴服線程和定時器 定時器可以在js中使用,但它不是js的一項功能,如果我們在非瀏覽器環(huán)...
    如201608閱讀 650評論 0 2
  • 一、什么是定時器 JS提供了一些原生方法來實現(xiàn)延時去執(zhí)行某一段代碼,下面來簡單介紹一下 setTimeout: 設(shè)...
    SSSSSSH閱讀 1,008評論 1 50
  • 從JS執(zhí)行機制說起 瀏覽器(或者說JS引擎)執(zhí)行JS的機制是基于事件循環(huán)。 由于JS是單線程,所以同一時間只能執(zhí)行...
    love2013閱讀 964評論 0 1
  • 定時器并不屬于JavaScript 雖然我們一直在JavaScript中使用定時器,但是它并不是javascrip...
    打鐵大師閱讀 930評論 0 5
  • 在談js定時器以前,我覺得有必要了解下javascript的事件運行機制,簡稱(javascript event ...
    JohnsonChe閱讀 1,021評論 0 2

友情鏈接更多精彩內(nèi)容