【JavaScript基礎】Js的定時器(你想看的原理也在喲)

【JavaScript基礎】Js的定時器(你想看的原理也在喲)

博客說明

文章所涉及的資料來自互聯網整理和個人總結,意在於個人學習和經驗彙總,如有什麼地方侵權,請聯繫本人刪除,謝謝!

說明

本章是經歷第二次翻新,時過一年,再看自己的文章,覺得需要做點什麼,它得豐富一點!篇幅半頁或者一頁,自己都感覺有點對不住自己。爲了對得住自己,加了原理解析和案例。知其然與所以然。

Js的定時器,是前端的基本工具,在日常的開發和工作上也會經常的使用到。前端的定時器有兩種,一種是一次性定時器,一種是重複性定時器。

一次性定時器setTimeout

標準:在指定的毫秒數後調用函數或計算表達式。

口語:使一段代碼在指定時間後運行。

語法

setTimeout(code,millisec,lang)
參數 描述
code 必需。要調用的函數後要執行的 JavaScript 代碼串。
millisec 必需。在執行代碼前需等待的毫秒數。
lang 可選。腳本語言可以是:JScript | VBScript | JavaScript

案例

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Js的定時器</title>
</head>

<body>

    <p>點擊按鈕,在等待 3 秒後彈出 "Hello"。</p>
    <button onclick="myFunction()">我是按鈕,點我</button>

    <script>
        function myFunction() {
            setTimeout(function () {
                alert("Hello")
            }, 1000 * 3);
        }
    </script>

</body>

</html>

重複性定時器setInterval

標準:按照指定的週期(以毫秒計)來調用函數或計算表達式。方法會不停地調用函數,直到 clearInterval() 被調用或窗口被關閉。

口語:可以使一段代碼每過指定時間就運行一次。

語法

setInterval(code,millisec,lang)
參數 描述
code 必需。要調用的函數或要執行的代碼串。
millisec 必須。週期性執行或調用 code 之間的時間間隔,以毫秒計。
lang 可選。 JScript | VBScript | JavaScript

案例

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Js的定時器</title>
</head>

<body>

    <input id="clock" />

    <button onclick="clearDate()">別變了,快停止吧,點我!</button>

    <script type="text/javascript">
        const id = setInterval(() => {
            const date = new Date();
            const time = date.toLocaleTimeString();
            document.getElementById("clock").value = time;
        }, 1000);

        function clearDate() {
            clearInterval(id)
        }
    </script>

</body>
  
</html>

時間的誤差

setInterval指定的是<span style="color: red">開始執行</span>之間的間隔,並不考慮每次任務執行本身所消耗的時間。因此實際上,兩次執行之間的間隔會小於指定的時間。

比如,setInterval指定每100ms執行一次,每次執行需要5ms,那麼第一次執行結束後95毫秒,第二次執行就會開始。如果某次執行耗時特別長,比如需要105毫秒,那麼它結束後,下一次執行就會立即開始。

爲了確保兩次執行之間有固定的間隔,可以不用setInterval,而是每次執行結束後,使用setTimeout指定下一次執行的具體時間。

var i = 1;
var timer = setTimeout(function() {
  alert(i++);
  timer = setTimeout(arguments.callee, 2000);
}, 2000);

消除定時器

在使用定時器的時候,需要有一個好的習慣,那就是清除定時器,<span style="color: red">特別是對於重複型定時器,一定要及時清除</span>。

定時器清除的方法

相對於兩種創建定時器的方法,Js也給出了相對應的清除方法,分別是clearTimeout(obj)clearInterval(obj)

在看到這兩種方法都是接收一個參數,這個參數就是定時器的標識,這個標識在使用定時器的時候被定義用來接收定時器方法的變量。

案例

// 一秒之後打印
const test1 = setTimeout(function(){
   console.log('hello world')
},1000);

// 每秒打印一次
const test2 = setInterval(function(){
	console.log('hello world')
},1000)

// 清理定時器
clearTimeout(test1);
clearInterval(test2)

原理

JavaScript語言特性

JavaScript是一門基於對象的弱類型語言,它作爲瀏覽器腳本語言,主要用途是負責與頁面的交互,以及操作DOM。

重點來了,<span style="color: red">JavaScript的執行環境是單線程的,即默認情況下是同步加載的,也就是說 JavaScript的加載是阻塞的</span>。在同一時間內JavaScript只能完成一件事,自上而下執行,下面的代碼等待上面的代碼解析完成。

在這種情況下,後面的代碼其實就是被阻塞了。阻塞就意味着等待,等待就意味着用戶體驗,用戶體驗一來,那必須得使勁想辦法,所以同步和異步出現了。

同步和異步

同步操作:隊列執行。

異步操作:併線執行。

異步的任務不具有阻塞效應。

同步任務都是在主線程中執行,形成了一個執行棧,直到主線程空閒時,纔會去事件隊列中查看是否有可執行的異步任務,如果有就推入主進程中。

異步任務在JavaScript中是通過回調函數實現異步的,回到本文的主題,一旦使用了setTimeout(),裏面的回調函數就是異步代碼,但是這裏面的代碼不會立馬執行,而是要等待主隊列爲空,並達到定的延時時間纔會執行。

運行機制

setTimeoutsetInterval的運行機制是,將指定的代碼移出本次執行,等到下一輪Event Loop時,再檢查是否到了指定時間。如果到了,就執行對應的代碼;如果不到,就等到再下一輪Event Loop時重新判斷。

這意味着,setTimeoutsetInterval指定的代碼,必須等到本輪Event Loop的所有同步任務都執行完,再等到本輪Event Loop的“任務隊列”的所有任務執行完,纔會開始執行。由於前面的任務到底需要多少時間執行完,是不確定的,所以沒有辦法保證在時間內執行。

案例

setTimeout(function() {
  console.log("異步任務執行");
}, 0);
 
function a(x) {
  console.log("a() 開始運行");
  b(x);
  console.log("a() 結束運行");
}
 
function b(y) {
  console.log("b() 開始運行");
  console.log(y);
  console.log("b() 結束運行");
}
 
console.log("同步任務開始");
a("hello world");
console.log("同步任務結束");
 
// 同步任務開始
// a() 開始運行
// b() 開始運行
// hello world
// b() 結束運行
// a() 結束運行
// 同步任務結束
// 異步任務執行

總結

  • JavaScript引擎是單線程,它會強制異步事件排隊等待執行;
  • setTimeout和setInterval執行原理是不一樣的,需要注意他們的執行時間的影響;
  • 如果一個一次性定時器(setTimeout)被阻塞了,它會等待直到有合適的執行時間(等待時間有可能比它定義的延遲時間長);
  • 如果重複性定時器(setInterval)回調函數執行時間很長(長於定義的間隔時間)的話,間隔定時器有可能無間隔的持續執行。

感謝

萬能的網絡

菜鳥教程

以及勤勞的自己,個人博客GitHub測試GitHub

公衆號-歸子莫,小程序-小歸博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章