使用setTimeout()代替setInterval()


背景:

  在JavaScript中,有兩種定時器:setTimeout()和setInterval();setTimeout()只執行一次定時操作,setInterval()執行無限次定時操作;但是大多數的觀點均是盡可能多使用setTimeout(),多次定數操作也是十使用setTimeout()代替setInterval()。

定時器的運行原理:

  要了解這樣做原因首先要知道定時器的工作方式:JavaScript語言是單線程語言,它有一個叫做執行隊列的東西來決定代碼的執行順序,而定時器的作用是:在特定的時間后將代碼插入到執行隊列。

  這里要特別理解:定時器setTimeout(function, Interval)這里的Interval是指當Interval個單位時間過去之后將代碼function插入到執行隊列中,而不是過去Interval個單位時間之后執行function代碼。也就說明代碼的執行的時間將大於等於Interval。

setInterval()定時器存在的問題:

  1.  定時器中的某些間隔會被跳過;

  2.  定時器之間的代碼間隔可能會比預期小;

  對於存在問題1的理解:如上圖所示:這個例子中的第 1 個定時器是在 205ms 處添加到隊列中的(即使任務隊列為空,0ms實際上是達不到的,因此至少為5ms),但是直到過了 300ms 處才能夠執行。當執行這個定時器代碼時,在 405ms 處又給任務隊列添加了另外一個副本。在下一個間隔,即 605ms 處,第一個定時器代碼仍在運行,同時在任務隊列中已經有了一個定時器代碼的實例。結果是,在這個時間點上的定時器代碼不會被添加到隊列中。結果在 5ms 處添加的定時器代碼結束之后,405ms 處添加的定時器代碼就立刻執行。

  對於存在問題2的理解:某個 onclick 事件處理程序使用 setInterval() 設置了一個 200ms 間隔的重復定時器。如果事件處理程序花了 300ms 的時間完成,同時定時器代碼也花了差不多的時間,就會同時出現跳過間隔且連續運行定時器代碼的情況。

個人疑惑之處:

  首先是對於setInterval的問題1,自己嘗試了寫演示代碼,發現最后都不能得到自己想要的輸出結果(最大可能是自己理解得不夠深),因為不知道用什么方法捕獲那個被跳過的代碼。最后我發現了一個特點:其實定時器忽略某個插入代碼,好像是無關緊要的,因為一般的我們插入的函數中都包含這一些操作函數,這些操作函數如果沒有執行,那么參數就不會發生變化,那么就不會影響最后的輸出結果。

  對於setInterval的問題2,自己寫出了演示代碼, 演示代碼如下:

 1 const log = console.log.bind(console)
 2 
 3 const timeDelay = (delayTime) => {
 4     let time = new Date()
 5     // console.log(time.getTime())
 6     while(true) {
 7         var t1 = new Date()
 8         if ((t1.getTime() - time.getTime()) >= Number(delayTime)) {
 9             // console.log(t1.getTime())
10             break
11         }
12     }
13 }
14 
15 const func = () => {
16     console.log("開始執行時間:" + new Date().toLocaleTimeString())
17     timeDelay(6000)
18     console.log("結束執行時間:" + new Date().toLocaleTimeString())
19 }
20 
21 // console.log(new Date().toLocaleTimeString())
22 
23 // setInterval(func, 2000)
24 // 開始執行時間:19:42:36
25 // 結束執行時間:19:42:42
26 // 開始執行時間:19:42:42 // 上一次的結束到下一次的開始, 間隔為0
27 // 結束執行時間:19:42:48
28 // 開始執行時間:19:42:50 // 上一次的結束到下一次的開始, 間隔為2(不太理解這里時間間隔為什么為2s)
29 // 結束執行時間:19:42:56
30 // 開始執行時間:19:42:56 // 上一次的結束到下一次的開始, 間隔為0
31 
32 
33 setTimeout(function () {
34     func()
35     setTimeout(arguments.callee, 2000)
36 },2000)
37 // 開始執行時間:19:44:45
38 // 結束執行時間:19:44:51
39 // 開始執行時間:19:44:53 // 上一次的結束到下一次的開始, 間隔為2
40 // 結束執行時間:19:44:59
41 // 開始執行時間:19:45:01 // 上一次的結束到下一次的開始, 間隔為2
42 // 結束執行時間:19:45:07
43 // 開始執行時間:19:45:09 // 上一次的結束到下一次的開始, 間隔為2

 

使用setTimeout代替setInterval的方法:

 1 let n = setTimeout(function () {
 2     // 判斷是否將操作代碼插入執行隊列
 3     if (boolean) {
 4         // 需要插入執行隊列的代碼
 5         function()
 6     }
 7     // 判斷是否進行定時器的遞歸
 8     if () {
 9         n = setTimeout(arguments.callee, interval)
10     }
11 }, interval)

  最好假如判斷條件,這樣方便控制整個定時器的循環

引用:

  1. JavaScript定時器及相關面試題:https://www.cnblogs.com/unclekeith/p/6443115.html

  

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM