1. 程式人生 > >用故事解析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>

導致的情況如下:

全劇終

八、彩蛋

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

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。
所以效果如下:

相關推薦

故事解析setTimeoutsetInterval(內含js執行任務佇列)

區別: setTimeout(fn,t): 延遲呼叫,超過了時間就呼叫回撥函式,返回一個id,使用clearTimeout(id)取消執行。 注意:取消了裡面的回撥函式就不執行了哦,而不是取消的時候就立即執行,下面有原始碼可以自己cv試一下。 setInterval(fn,t): 迴圈呼叫,有周期性的呼叫回撥

js執行非同步並不衝突

眾所周知,js是單執行緒的,但是我們又經常說js非同步,這是為什麼呢? 實際上瀏覽器的渲染過程是多執行緒的,它不只有js一個執行緒,它還有GUI渲染執行緒、事件觸發執行緒、定時觸發器執行緒、非同步http請求執行緒等執行緒 js一次只能執行一個任務,當他有許

JavaScript——從setTimeout()的執行了解js執行非同步

眾所周知,JavaScript是單執行緒的,那麼到底什麼是單執行緒呢?今天我們就用setTimeout()舉例,看看單執行緒到底是什麼樣的。 單執行緒,從名字就能知道,它只有一個主執行緒。單執行緒就意味著,所有任務需要排隊,前一個任務結束,才會執行後一個任務。如果前一個任務

js執行非同步

前言 說到js的單執行緒(single threaded)和非同步(asynchronous),很多同學不禁會想,這不是自相矛盾麼?其實,單執行緒和非同步確實不能同時成為一個語言的特性。js選擇了成為單執行緒的語言,所以它本身不可能是非同步的,但js的宿主環境(比如瀏覽

js執行瀏覽器的多執行

js執行是單執行緒:(傳送請求,接受請求,渲染頁面,執行js等等這些就是一個個執行緒。) JS引擎 通常講到瀏覽器的時候,我們會說到兩個引擎:渲染引擎和JS引擎。渲染引擎就是如何渲染頁面,Chrome/Safari/Opera用的是Webkit引擎,IE用的是Triden

Python-爬取妹子圖(執行執行版本)

一、參考文章     Python爬蟲之——爬取妹子圖片     上述文章中的程式碼講述的非常清楚,我的基本能思路也是這樣,本篇文章中的程式碼僅僅做了一些異常處理和一些日誌顯示優化工作,寫此文章主要是當做筆記,方便以後查閱,修改的地方如下: 1、異常處理

Python-爬取校花網視訊(執行執行版本)

一、參考文章     python爬蟲爬取校花網視訊,單執行緒爬取     爬蟲----爬取校花網視訊,包含多執行緒版本     上述兩篇文章都是對校花網視訊的爬取,由於時間相隔很久了,校花網上的一些視訊已經不存在了,因此上

02-node.js 執行,‘ 非同步’非阻塞io

1、基本概念     同步:多個任務順序執行     非同步:多個任務並排執行 2、node的併發實現原理     Node JS是單執行緒應用程式,但它通過事件和回撥概念,支援併發。 由於Node JS每一個API是非同步的,作為一個單獨的執行緒,它使用非同步函

python-同步非同步、阻塞非阻塞、序列並行、並行併發、密集型、執行程序的相關概念

1. 同步和非同步   關注的是訊息的通訊機制,描述的是一種行為方式,是多個任務之間的關係。 ① 同步: 呼叫者主動等待被呼叫方返回結果,在沒有返回結果之前,就一直專職等待。 千萬不要把計算機中“同步”理解成“同時執行”。 ② 非同步:呼叫者傳送請求請求,不會專職等待

以生活的例子說明執行執行

以生活例子說明單執行緒與多執行緒 轉載自:書圈 1. 程式設計的目標 在我看來單從程式的角度來看,一個好的程式的目標應該是效能與使用者體驗的平衡。當然一個程式是否能夠滿足使用者的需求暫且不談,這是業務層面的問題,我們僅僅討論程式本身。圍繞兩點來展開,效能與

python 執行執行

單執行緒, 在好些年前的MS-DOS時代,作業系統處理問題都是單任務的,我想做聽音樂和看電影兩件事兒,那麼一定要先排一下順序。 #coding=utf-8 import threading from time import ctime,sleep def

JavaScript的執行非同步

前言 我們都知道JavaScript是單執行緒語言,但有沒有想過JavaScript為什麼是單執行緒語言,而不採用效率更高的多執行緒呢?並且一個單執行緒語言又是如何能夠實現非同步操作的呢?接下來我們詳細討論JavaScript的單執行緒和非同步實現(注:理論層面的實現,非語言層面)。

SpringBoot 定時執行配置 執行執行

Spring Boot 的定時任務: 第一種:把引數配置到.properties檔案中: 程式碼: package com.accord.task;   import java.text.SimpleDateFormat; import java.util.Date;

C++11:基於std::queuestd::mutex構建一個執行安全的佇列

C++中的模板std::queue提供了一個佇列容器,但這個容器並不是執行緒安全的,如果在多執行緒環境下使用佇列,它是不能直接拿來用的。 基於它做一個執行緒安全的佇列也並不複雜。基本的原理就是用std::mutext訊號量對std::queue進行訪問控制,以

js執行與java多執行、同步與非同步

       寫這篇部落格源於想對比一下單執行緒js和多執行緒java兩種語言的區別。       定義區:            單執行緒:只能執行一個任務,只有在完成執行後,才能繼續執行其他的任務。            多執行緒:有多個執行緒,可以同時執行多個任務。

Spring Boot 定時任務執行執行

Spring Boot 的定時任務: 第一種:把引數配置到.properties檔案中: 程式碼: package com.accord.task; import java.text.SimpleDateFormat; import java.util.Date; im

C# 執行執行下的例模式的實現

該單例模式是執行緒不安全的,只能在單執行緒下執行,在多執行緒中如果被兩個執行緒同時呼叫Instance屬性時,此時兩個執行緒判斷 if (_instance==null)時都會返回true,就會建立兩個例項。public class Singleton{ /// <

淺析 Node.js 執行模型

總結筆記:對於每個使用者請求,由主執行緒接收並存放於一個事件佇列中(不做任何處理),當無請求發生時,即主執行緒空閒,主執行緒開始迴圈處理事件佇列中的任務: 對於非阻塞JS程式: 1、若某事件需要I/O操作,則主執行緒發出I/O請求,然後繼續執行,由底層

執行不能不知道的之執行執行的比較

早期的計算硬體十分複雜,但是作業系統執行的功能確十分的簡單。那個時候的作業系統在任一時間點只能執行一個任務,也就是同一時間只能執行一個程式。多個任務的執行必須得輪流執行,在系統裡面進行排隊等候。 栗

理解js執行非同步機制

1.最近在維護一個專案,用到的主要語言是JS。因此在寫需求功能時對JS的非同步有了進一步的理解。JS是單執行緒的,但是JS是可以非同步的。setTimeout(function(){console.log();},1000)  執行setTimeout時,會把裡面的匿名函式放