chrome下的Javascript的使命機制

Javascript Evet Loop 模子

setTimeout()最短的事宜距離是4ms
setInterval()最短的事宜距離是10ms
以上這個理論橫豎我是沒有考證過

Exemple 1

——question:——

console.log('start');

const interval = setInterval(() => {  
console.log('setInterval');
}, 0);

setTimeout(() => {  
console.log('setTimeout 1');
Promise.resolve()
    .then(() => {
        console.log('promise 3');
    })
    .then(() => {
        console.log('promise 4');
    })
    .then(() => {
        setTimeout(() => {
        console.log('setTimeout 2');
        Promise.resolve()
            .then(() => {
                console.log('promise 5');
            })
            .then(() => {
                console.log('promise 6');
            })
            .then(() => {
                clearInterval(interval);
            });
        }, 0);
    });
}, 0);

Promise.resolve()
    .then(() => {  
        console.log('promise 1');
    })
    .then(() => {
        console.log('promise 2');
    });
    

——非chrome result:——

    
start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
promise 5
promise 6

——node.js result——

start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
setInterval
promise 5
promise 6

——windows/mac chrome result:——

start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setInterval
setTimeout 2
promise 5
promise 6

在windows chrome里setTimeout 2上方會湧現一連兩個setInterval,有些新鮮,在mac的chrome和windows的firefox都是一般的輸出(發作毛病的window chrome版本號為:Version 65.0.3325.181 (Official Build) (64-bit))

經由更屢次測試,關於上述結論做以下改正:
windows/mac chrome 運轉這段代碼有時會湧現雙setInterval狀況,而另一些時刻則和非chrome瀏覽器環境運轉無異。這類狀況筆者臨時還沒有找到準確的答案。

——windows chrome exemple:——

console.log('start');

var nerdPointer;
function nerdFunc(){
    console.log('setInterval');
    nerdPointer = setTimeout(nerdFunc,0);
}
setTimeout(nerdFunc,0);

setTimeout(() => {  
console.log('setTimeout 1');
Promise.resolve()
    .then(() => {
        console.log('promise 3');
    })
    .then(() => {
        console.log('promise 4');
    })
    .then(() => {
        setTimeout(() => {
        console.log('setTimeout 2');
        Promise.resolve()
            .then(() => {
                console.log('promise 5');
            })
            .then(() => {
                console.log('promise 6');
            })
            .then(() => {
                clearInterval(nerdPointer);
            });
        }, 0);
    });
}, 0);

Promise.resolve()
    .then(() => {  
        console.log('promise 1')
    })
    .then(() => {
        console.log('promise 2')
    });

windows chrome下跑上面這段代碼並不會失足

Exemple 2

——question:——

function expendTime(k){
    console.log((new Date()).getTime());
    while(k < 1000){
        for(var j = 2; j < k; j++){
            if(k%j == 0){
                break;
            }
            if(j == k-1){
                console.log(k)
            }
        }
        k++;
    }
    console.log((new Date()).getTime());
    clearInterval(t);
}

var t = setInterval(expendTime,15,3);

——result:——

效果:只舉行了一次expendTime()盤算

mac 17關於expendTime()的運轉事宜大概在30ms朝上,setInterval()設定的距離是15ms,所以在expendTime()沒有實行終了的時刻並沒有再增加一個expendTime()task queue中(函數末端setInterval()被消滅),所以效果才只舉行了一次expendTime()的盤算

Example 3

Example 2中的代碼做以下修正,再次舉行測試

——question:——

function expendTime(k){
    console.log((new Date()).getTime());
    while(k < 10000){
        for(var j = 2; j < k; j++){
            if(k%j == 0){
                break;
            }
            if(j == k-1){
                console.log(k)
            }
        }
        k++;
    }
    console.log((new Date()).getTime());
}

var t = setInterval(expendTime,15,3);
setTimeout(function (){clearInterval(t);},30);

——chrome result:——

輸出了兩次后被住手

——非chrome result:——

輸出一次后住手,證實在大多數瀏覽器上,Exemple 2中的結論是準確的

——conclusion:——

又是在chrome上湧現了不合理的詭異的行動。和規範中event loop的理論相悖

Example 4

——question:——

function fn1() {
    for (var i = 0; i < 4; i++) {
        var tc = setTimeout(function(i) {
            console.log(i);
            clearTimeout(tc)
        }, 10, i);
    }
}

function fn2() {
    for (var i = 0; i < 4; i++) {
        var tc = setInterval(function(i, tc) {
            console.log(i);
            clearInterval(tc)
        }, 10, i, tc);
    }
}
fn1();
fn2();

——answer:——

這題考核了對閉包和定時器別的另有js實行遞次的明白。
先來說說fn1,假如把clearTimeout去掉,置信人人肯定很熟悉,都會說10ms耽誤後會順次輸出0,1,2,3。
然則,請注意這裏加了個clearTimeout,假如你去控制台試驗的話會發明只輸出了0,1,2,那3呢?
先別急,請聽我逐步道來:
請注意:這個tc是定義在閉包表面的,也就是說tc並沒有被閉包保留,所以這裏的tc指的是末了一個輪迴留下來的tc,所以末了一個3被消滅了,沒有輸出。

再來看看fn2,能夠發明區分就是把setTimeout改成了setInterval,同時把定時器也傳到了閉包里。
那末效果又會有什麼差別呢?假如親身去試驗的同硯就會發明輸出0,1,2,3,3,3…。
什麼鬼?為毛末了一個定時器沒被刪除。說實話,我在這裏也想了良久,為什麼末了一個定時器沒被刪除。厥後我為了調試方便把i<4改成了i<2並把觸發時候改成3s,在瀏覽器中單步調試,發明3s后第一次觸發還調函數實行的時刻tc的值是undefined第二次觸發的時刻有值了。這個時刻我頓悟,這和順序的實行遞次有關。我們曉得js一般狀況下是從上到下,從右到左實行的。
所以這裏每次輪迴先設置定時器,然後把定時器的返回值賦值給tc。在第一次輪迴的時刻tc並沒有被賦值,所以是undefined,在第二次輪迴的時刻,定時器實在清算的是上一個輪迴的定時器。所以致使每次輪迴都是清算上一次的定時器,而末了一次輪迴的定時器沒被清算,致使一向輸出3。

    原文作者:小杺
    原文地址: https://segmentfault.com/a/1190000014665591
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞