iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
0
自我挑戰組

花三十天找到 JavaScript 沙漠中的綠洲系列 第 21

21 倒數計時...開始!論 requestAnimationFrame、 setInterval 和 setTimeout

前言

昨天我們成功從電腦那取得了時間,但是時間不會動...今天就繼續跟我一起勇闖時間城,把停滯的時間找回來吧哈哈哈!(天啊今天的開場白也太中二)

setTimeout

語法: setTimeout(function,毫秒)

之前在 C3.js 曾經提過這個東西,當你想要延遲一下下,才執行某函式時,便可以使用 setTimeout() 。在括號中放入你要執行的函式名稱,以及你要多久後執行他。注意,這裡是用毫秒來當單位的,如果要一秒後執行,請打 1000 ,依此類推。就像下面的範例:

function example(){
    console.log("aloha");
}

setTimeout(example, 1000);

為了方便隨時能呼叫或取消 setTimeout ,我們可以為 setTimeout 宣告變數。

function example(){
    console.log("aloha");
}

const ref = setTimeout(example, 1000);

如果要取消 setTimeout ,只要在 setTimeout 下方加上 clearTimeout( setTimeout 的變數名稱) 就可以了。如果上面講得太抽象,請看以下範例:

function example(){
    console.log("aloha");
}

const ref = setTimeout(example, 1000);

clearTimeout(ref);

相信上面應該不難,那如果我們想要每隔一段時間,就執行一次函式,不斷執行呢?

setInterval

語法: setInterval(function,毫秒)

基本上跟 setTimeout 大同小異,讓我們直接進入範例:

function example2(){
    console.log("aloha");
}

const ref2 = setInterval(example2, 1000); //每隔一秒就執行一次 function example2

clearInterval(ref2); //加上這句時, setInterval 不再執行

requestAnimationFrame

都已經教了兩種,感覺也夠用了,幹嘛還要看第三種?其實,雖然 setInterval 和 setTimeout 使用起來非常簡單,卻會造成時間誤差。

requestAnimationFrame 用起來跟 setTimeout 很像,都是執行一次,只是他不需要設定時間間格。並且可以解決延遲的情況。

語法: requestAnimationFrame(function);

透過這個方法,通知瀏覽器我們要產生動畫,並在下次重整前呼叫函式來更新動畫。這就有點像是製作逐格動畫時,跳完這一頁的畫面,通知系統換下一張的畫面一樣。不僅如此,這個語法還有一個好處,就是當使用者沒有在使用頁面時,瀏覽器會暫停呼叫。

讓我們來看看相關範例:

function example3(){
    console.log("aloha");
}

requestAnimationFrame(example3);

當然,你也可以宣告他,方便後續呼叫或取消行為。

function example3(){
    console.log("aloha");
}

const ref3 = requestAnimationFrame(example3);

cancelAnimationFrame(ref3);

如果你要讓他不停地跑,可以這樣寫:

function example3(){
  console.log("aloha");
}

function example3Loop(){
  example3();
  requestAnimationFrame(example3Loop);
}

example3Loop();

在上面的範例中,瀏覽器跑得多快,他重新跑/繪製的速度就有多快。

requestAnimationFrame、 setInterval 和 setTimeout 的概念大概就是這些。事不宜遲,讓我們來改寫昨天的時鐘!

實際應用

setInterval

雖然有時間誤差的問題,還是實際寫一次給大家看要怎麼使用:

function count(){
  let time = new Date();
  let year = time.getFullYear();
  let month = time.getMonth();
  let date = time.getDate();
  let day = time.getDay();
  let hours = time.getHours();
  let minutes = time.getMinutes();
  let seconds = time.getSeconds();
  let milliseconds = time.getMilliseconds();

  const dayName = ["日","一","二","三","四","五","六"] //從0開始計算,所以日要放在第一個,不然會加一

  const word = document.querySelector('.word');
  word.innerHTML = `
    現在是標準時間 ${year} 年 ${month+1} 月 ${date} 日星期${dayName[day]} <br/>
    ${hours} : ${minutes} : ${seconds} : ${milliseconds}
  `;
};

setInterval(count,1000);

requestAnimationFrame

答應我你沒有跳過上面就直接來看這裡...不然你就會少貼到東西。用 requestAnimationFrame 寫的話是這樣,上方 function count 因為重複我就省略不打了:

function countloop(){
  count();
  requestAnimationFrame(countloop);
}

countloop();

希望你喜歡今天的文章!

學習與參考資料

JS 學徒特訓班教學影片及練習題 42 關
Meet the Timers: setTimeout, setInterval, and requestAnimationFrame: https://www.youtube.com/watch?v=zucCjXApXOU
網頁前端工程入門:JavaScript 自動排程 By 彭彭: https://www.youtube.com/watch?v=I93LFPtBgL8&list=PL-g0fdC5RMbpqZ0bmvJTgVTS4tS3txRVp&index=22
MDN Window.requestAnimationFrame(): https://developer.mozilla.org/zh-TW/docs/Web/API/Window.requestAnimationFrame
BOM系列第二篇之定時器requestAnimationFrame: https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/261758/
神奇的requestAnimationFrame解決傳統定時器bug: https://www.twblogs.net/a/5d85b8cabd9eee53270007b1


上一篇
20 newDate()
下一篇
22 Github
系列文
花三十天找到 JavaScript 沙漠中的綠洲35

尚未有邦友留言

立即登入留言