Javascript Evet Loop 模子
setTimeout()
最短的事宜距離是4mssetInterval()
最短的事宜距離是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。