【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(),裏面的回調函數就是異步代碼,但是這裏面的代碼不會立馬執行,而是要等待主隊列爲空,並達到定的延時時間纔會執行。
運行機制
setTimeout
和setInterval
的運行機制是,將指定的代碼移出本次執行,等到下一輪Event Loop時,再檢查是否到了指定時間。如果到了,就執行對應的代碼;如果不到,就等到再下一輪Event Loop時重新判斷。
這意味着,setTimeout
和setInterval
指定的代碼,必須等到本輪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)回調函數執行時間很長(長於定義的間隔時間)的話,間隔定時器有可能無間隔的持續執行。
感謝
萬能的網絡
公衆號-歸子莫,小程序-小歸博客