天天看點

用故事解析setTimeout和setInterval(内含js單線程和任務隊列)差別:八、彩蛋

用故事解析setTimeout和setInterval(内含js單線程和任務隊列)

差別:

setTimeout(fn,t):

延遲調用,超過了時間就調用回調函數,傳回一個id,使用clearTimeout(id)取消執行。

注意:

取消了裡面的回調函數就不執行了哦,而不是取消的時候就立即執行,下面有源碼可以自己cv試一下。

setInterval(fn,t):

循環調用,有周期性的調用回調函數,傳回一個id,使用clearInterval(id)取消執行。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
<script>
console.log('333333333333333333333')
var aa =setTimeout(()=>{
    console.log("11111111111111")
},6000)
setTimeout(()=>{
    clearTimeout(aa)
    console.log("2222222222")
},3000)
</script>
</head>
<body>

</body>
</html>
           

在學習這兩種延遲函數之前要最好是先了解一下JS單線程和任務隊列;

舉個栗子:

在廣場上,隻有一家一點點奶茶店(

cpu

),然後我(

一個任務

)要去買奶茶(

執行這個任務

),隻能排一條隊(

js的單線程機制

),雖說排隊(

主線程

)的人很多,但是一點點從業人員工作速度确實很快,一般的人付完現金就完了(

synchronous同步任務

)。

但是到了我的時候,我想用支付寶支付,但是打開支付寶需要網絡,需要等待支付寶軟體打開(

asynchronous異步任務,等待IO裝置傳回結果

),但是為了不影響隊列後面的排隊者的速度,是以一點點的從業人員讓我去旁邊的隊列裡(

任務隊列

)去等待,這個隊列裡面有加我一起有三個人在啟動支付寶,我排在第三。

然後一段時間過後,我的和第一個人支付寶打開了(

IO裝置傳回結果了

),第二個人沒打開,我和第一個人就把二維碼展示出來(

在任務隊列中添加一個事件,表示相關異步任務可以進入主線程執行了

),但是這個時候主隊列裡面還有一些人在買奶茶,是以,現在從業人員顧不上我。

然後我們就隻能一直等待,直到主隊列裡面買奶茶的人都走光了,這個時候從業人員就把我和第一個人加入主隊列中,然後我和第一個人就相繼都買到奶茶了,主隊列又沒有人了,于是從業人員又去問第二個人二維碼有沒有出來,(

這個過程叫Event Loop(事件循環)

),至此基本的單線程和任務隊列就完了,下面再了解一下定時器的特殊原理。

setTimeout(fn,t)

同樣的,又是我(

setTimeout(fn,20)函數

)去買奶茶,我首先還是去排隊,到我的時候我說我現在不想買,我要等到20(

設定的時長

)毫秒之後再買,從業人員就說,好,那你去任務隊列裡面去等20毫秒吧,然後我就屁颠屁颠的去了。

20毫秒後,還是老樣子,從業人員要等到主隊列裡面人都走完了再把我拉到主隊列裡面去,是以我實際等待的時間=我設定的時間+設定時間到了之後主隊列裡面執行的時間,但是慶幸的是從業人員工作速度非常快,是以一般主隊列裡面是沒有人的。

注意:

1、是以即使你設定逾時時間為0,從業人員也不會立馬執行你哦,還是會把你加到任務隊列中的,誰叫你是asynchronous(異步任務)

2、你設定逾時時間有用嗎?實際上是沒有生效的,因為html5标準規定了setTimeout設定逾時時間最小值是4毫秒,如果低于這個值就會自動增加,老版本浏覽器更将是把最短時間設為10毫秒,而最要命的是,如果涉及到DOM的變動的都是16毫秒一次。

setInterval(fu,t)

同樣的,鳴人(

setInterval(fn,1000)函數

)去買奶茶,首先還是去排隊,到鳴人的時候,它不僅要在1秒鐘之後買,還要影分身出很多鳴人相繼在1、2、3、4...之後買,從業人員同樣要他和他的影分身在任務隊列後面排隊等會,正常情況下,主隊列沒人了,鳴人和他的影分身們也會在規定的時間裡面相繼執行。

那麼問題來了

假如每個鳴人都很喜歡逼逼叨叨,那麼就會發生這樣子的情況:

當一秒鐘後第一個鳴人從任務隊列中到主隊列中的時候,就一直跟從業人員逼逼叨叨(

發生阻塞了,例如遇到循環不完的for

),直到第四秒鐘才說完(也就是b了3秒鐘),這個時候第二個鳴人已經超過預定時間的兩秒鐘了,然後等到第二個鳴人和從業人員聊得時候又逼逼叨叨不停,又要b3秒鐘,是以第二個鳴人會在第7秒b完,同理,第三個和第四個分别在第10秒和第13秒b完。

鳴人逼逼叨叨的過程如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>uaoie.top</title>
<script>
console.log('333333333333333333333')
var y=0;
var x = new Date().getTime();
var d=setInterval(a,1000);
function a() {
    y++;
   sleep(3000);
    if(y>=4){
        clearInterval(d)
    }
console.log(new Date().getTime()-x);
}
function sleep(sleepTime){
    var start=new Date().getTime();
    while(true){
        if(new Date().getTime()-start>sleepTime){
            break;    
        }
    }
}
</script>
</head>
<body>
</body>
</html>
           

導緻的情況如下:

用故事解析setTimeout和setInterval(内含js單線程和任務隊列)差別:八、彩蛋

全劇終

八、彩蛋

現在我們可以很輕松的分析一下下面代碼的原理(雖然我們都知道結果):

var aa=new Date().getTime()
for (var i = 0; i < 4; i++) {
    setTimeout(function() {
        console.log(new Date().getTime() -aa, i);
    }, 1000);
}
console.log(new Date().getTime() -aa, i);
           

先執行第一行,完了後執行for,循環4次也就是執行4次setTimeout函數,這個4個函數同時放在任務隊列中。

然後再執行最下面的config,是以會先列印0秒和4。

然後等到一秒後,setTimeout函數從任務隊列中出來到主隊列,輸出的是1秒和4。

是以效果如下:

用故事解析setTimeout和setInterval(内含js單線程和任務隊列)差別:八、彩蛋

posted on 2019-09-03 14:51  買辣椒也用券 閱讀( ...) 評論( ...) 編輯 收藏

轉載于:https://www.cnblogs.com/Juaoie/p/11446302.html