亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript定時器實現(xiàn)的原理分析

 更新時間:2016年12月06日 08:28:45   作者:謝燦勇  
JavaScript中的定時器大家基本在平時的開發(fā)中都遇見過吧,但是又有多少人去深入的理解其中的原理呢?本文我們就來分析一下定時器的實現(xiàn)原理、定時器的妙用、定時器使用注意事項,有興趣的朋友可以看下

JavaScript中的定時器大家基本在平時的開發(fā)中都遇見過吧,但是又有多少人去深入的理解其中的原理呢?下面我們就來分析一下定時器的實現(xiàn)原理。

一、儲備知識

在我們在項目中一般會遇見過這樣的兩種定時器,第一種是setTimeOut,第二種是setInterval,這兩種定時器有如下的區(qū)別:

1、setTimeout允許設(shè)置一個超時對象,超時后執(zhí)行這個對象,但是只執(zhí)行一次,無周期

2、setInternval允許設(shè)置一個超時對象,超時后執(zhí)行這個對象,周期等于超時對象指定的時間,周期為無限循環(huán)

舉一個簡單的例子來說明一下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>blog案例</title>
</head>
<body>
 <script type="text/javascript">
  setTimeout("alert('this is test')",2000);
  setInterval("console.log('demo');",1000);
 </script>
</body>
</html>

這個運行后的結(jié)果是彈出了一次對話框,然后在控制臺可以看到每1秒鐘會向其中輸出demo字樣

二、定時器原理初識

那么問題來了,如下的代碼運行的時候會出現(xiàn)什么情況呢?

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>blog案例</title>
</head>
<body>
 <script type="text/javascript">
  setTimeout("alert('定時器!')",0);
  alert("測試")
 </script>
</body>
</html>

是先執(zhí)行alert("測試"),還是先執(zhí)行alert("定時器")呢,那么我們就來運行一下吧!

運行后的結(jié)果是先彈出測試字樣的彈出框,然后才彈出定時器字樣的彈出框,為什么會這樣呢?不是定時器的時間為0就即可執(zhí)行嗎?

答案不是這樣的,因為JS眾所周知是單線程的,所以很多人會認為在上面的例子中會先阻塞等待定時器執(zhí)行完成后再執(zhí)行下面的語句,但是這個也就是單線程的一個缺陷之一吧,為了解決這個問題,引入了異步機制。異步機制主要是利用一個我們平時很少去關(guān)注的一個知識點——瀏覽器的多線程。究竟什么是瀏覽器的多線程呢?

三、瀏覽器的多線程

 這里我們就來講解一下,眾所周知,JS是單線程的,但是對于瀏覽器來說JS的執(zhí)行只不過是在瀏覽器眾多現(xiàn)成中的一條,我們稱之為JS引擎線程。而瀏覽器的其他線程則是通過JS引擎線程在執(zhí)行到某個特定的功能之后指定給瀏覽器的對應(yīng)線程。具體的原理詳見圖示:

 從這張圖我們可以知道JS引擎線程首先執(zhí)行回調(diào)函數(shù)塊,然后是執(zhí)行點擊事件回調(diào),接著是執(zhí)行定時器的線程,最后在執(zhí)行其他的線程。

以下面的代碼我們來分析一下:

setTimeout("alert('定時器!')",0);
alert("測試")

首先JS線程讀取到setTimeout定時器,這個時候就會執(zhí)行瀏覽器的線程,然后跳過定時器繼續(xù)執(zhí)行,這個時候你就看到了彈出框的內(nèi)容為測試,然后因為定時器的時間為0,所以一執(zhí)行定時器線程就會即可將彈出框為定時器字樣的任務(wù)添加到主線程(JS引擎線程)的隊列之后,等待JS引擎的調(diào)用,這個時候我們看到的結(jié)果是先彈出測試,然后再彈出定時器

另外我們要注意在HTML5規(guī)范中規(guī)定定時器的定時時間不能小于4ms,如果是小于4ms,則默認為4ms,所以在這個例子中的0,默認的是4ms,但是這個在不通過的瀏覽器中的表現(xiàn)是不同的,但是這個一般在項目中是沒有什么印象的,這個只是僅做了解即可。

 好的我們將上面的代碼改寫成這樣,然后我們再來看看效果:

 <script type="text/javascript">
  console.time("test");
  setTimeout("for(var i=0;i<1000;i++)console.log('定時器!');",1000);
  console.log("測試");
  console.timeEnd("test");
 </script>

    運行后的結(jié)果如下:

    這里有幾個知識點:

1、console.time和console.timeEnd這兩個方法是可以獲取在其中間執(zhí)行的語句所用的時間,從圖中我們可以知道test執(zhí)行的時間在1ms左右,然而定時器的定時時間是在1000ms左右所以這兩個語句只能計算當(dāng)前引擎的執(zhí)行時間,換句話說就是在瀏覽器中的定時器模塊的運行時間是這樣是沒法計算的

2、另外我們可以看到一個現(xiàn)象就是定時器在執(zhí)行的時候不是一千個定時器的字樣全都一次性的打印出來,而是幾百幾百的增加,這個是為什么呢?這里就涉及到了另外的一個問題,如果是定時器的時間到了,但是定時器中的任務(wù)沒有執(zhí)行完成這個時候會怎樣?

我們上面說過就是定時器的時間到了的情況下,就會向JS引擎線程添加任務(wù),不論任務(wù)里面的語句是否執(zhí)行完成,都會像JS引擎線程隊列中添加,但是剩下的未執(zhí)行完成的語句怎么辦呢?

程序執(zhí)行到了定時器任務(wù)的時候,就會先把已經(jīng)在定時器模塊執(zhí)行過的語句加載一次,然后是繼續(xù)執(zhí)行定時器模塊的剩余語句。(定時器模塊向JS引擎中添加的任務(wù)相當(dāng)于就是C語言中的一個指針,指向的是定時器模塊)

所以,setTimeout我們可以定義為:

在指定時間內(nèi), 將任務(wù)放入事件隊列,等待js引擎空閑后被執(zhí)行.

四、setInterval的使用

setInterval最基礎(chǔ)的使用方法是直接當(dāng)一個循環(huán)定時器使用,這里就不舉例說明

對于setInterval(fn, 100)容易產(chǎn)生一個誤區(qū):并不是上一次fn執(zhí)行完了之后再過100ms才開始執(zhí)行下一次fn。 事實上,setInterval并不管上一次fn的執(zhí)行結(jié)果,而是每隔100ms就將fn放入主線程隊列,而兩次fn之間具體間隔多久就不一定了,跟setTimeout實際延遲時間類似,和JS執(zhí)行情況有關(guān)。具體的延遲效果與內(nèi)存等因素有關(guān)。

五、定時器的可靠性

雖說定時器在大部分的情況下都是趨于穩(wěn)定的,但是定時器在使用的時候也存在著一些誤差

如下所示:

<script type="text/javascript">
  var time1 = new Date().getTime();
  setInterval(function(){
   var time2 = new Date().getTime();
   console.log("setInterval執(zhí)行的差值時間:"+(time2-time1));
  },1000);
 </script>

運行的結(jié)果如下:

從圖中我們基本可以看出定時器存在著一些小小的誤差就比如第一次的運行時間為1001ms比我們設(shè)定的時間多出了1ms,所以得出結(jié)論:定時器不是完全的可靠的,存在極小的誤差。這個還是在chrome瀏覽器上面測試的結(jié)果,換是在IE瀏覽器測試那又如何呢?

結(jié)果顯示,在IE瀏覽器下面的誤差更大

六、定時器的妙用

 定時器在項目中除了可以作為定時的作用外還可以用來做耗時代碼的優(yōu)化:

 我們假設(shè)有這樣的一個場景,就是在某個頁面中要渲染50萬個節(jié)點,這個時候?qū)τ谝话愕捻椖恐?,直接渲染是不可取的,因為這個時候會占用過多的內(nèi)存,導(dǎo)致瀏覽器出現(xiàn)了卡死的狀態(tài),用戶誤以為是頁面卡死而  直接關(guān)閉瀏覽器或者殺死進程,即使是用戶不關(guān)閉頁面這樣給用戶的體驗也是不好的,這個時候我們要怎樣來解決這個問題呢,我們可以利用定時器來優(yōu)化這個問題首先我們可以把50萬個節(jié)點分成多組,每組渲染  的節(jié)點數(shù)不要過多,然后通過setInterval來進行循環(huán)這個既不阻塞JS引擎線程的運行,又不可以提高渲染的消耗時間。從而達到最終的優(yōu)化渲染。

七、定時器使用注意事項

 如果是項目中有對個定時器的參與那么記得在一個定時器執(zhí)行結(jié)束的時候記得要調(diào)用clearInterval或clearTimeout這兩個方法來清除定時器,以免定時器之間互相干擾出現(xiàn)一些抓摸不定的現(xiàn)象

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,同時也希望多多支持腳本之家!

相關(guān)文章

  • JavaScript 異步調(diào)用

    JavaScript 異步調(diào)用

    本文通過一個小小題目逐步走進javascript 異步調(diào)用問題,本文附有解答過程,感興趣的朋友一起看看吧
    2017-10-10
  • 詳解Typescript中奇怪的賦值操作

    詳解Typescript中奇怪的賦值操作

    這篇文章主要來和大家討論一下typescript中一些奇怪的賦值語句,探索其背后原因,更深入的了解typescript作為一個結(jié)構(gòu)化系統(tǒng)的特性,感興趣的可以了解下
    2024-02-02
  • JavaScript中的eval()函數(shù)使用介紹

    JavaScript中的eval()函數(shù)使用介紹

    這篇文章主要介紹了JavaScript中的eval()函數(shù)使用介紹,本文講解了eval()的使用、eval()的返回值、變量環(huán)境(variable environment)等內(nèi)容,需要的朋友可以參考下
    2014-12-12
  • 15個非常實用的JavaScript代碼片段

    15個非常實用的JavaScript代碼片段

    這篇文章主要為大家詳細介紹了15個非常實用的JavaScript代碼片段,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Bootstrap模態(tài)框水平垂直居中與增加拖拽功能

    Bootstrap模態(tài)框水平垂直居中與增加拖拽功能

    最近開發(fā)一個CMS系統(tǒng)使用上了Bootstrap,在開發(fā)一個添加某些選項時,打算彈出一個模態(tài)框,但是發(fā)現(xiàn),模態(tài)框不會垂直居中到屏幕上,而是在屏幕上方,通過查閱資料才解決此問題,下面小編給大家分享解決思路
    2016-11-11
  • 原生js實現(xiàn)焦點輪播圖效果

    原生js實現(xiàn)焦點輪播圖效果

    本文主要分享了原生js實現(xiàn)焦點輪播圖效果的示例代碼,并解析了實例中的注意點。具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • JavaScript中?this?的綁定指向規(guī)則

    JavaScript中?this?的綁定指向規(guī)則

    這篇文章主要介紹了JavaScript中?this?的綁定指向規(guī)則,this的指向問題存在各種各樣的,關(guān)于如何綁定指向,下面文章作簡單介紹需要的小伙伴可以參考一下
    2022-06-06
  • 純 JS 實現(xiàn)放大縮小拖拽功能(完整代碼)

    純 JS 實現(xiàn)放大縮小拖拽功能(完整代碼)

    這篇文章主要介紹了純js實現(xiàn)放大縮小拖拽功能,文中給大家提到了在開發(fā)過程中遇到的一些問題及解決方法,需要的朋友可以參考下
    2019-11-11
  • 微博@符號的用戶名提示效果。(想@到誰?)

    微博@符號的用戶名提示效果。(想@到誰?)

    相信你老早就在騰訊或者新浪的微博上體驗到了,@符號在微博時代的便捷呼叫。
    2010-11-11
  • JavaScript數(shù)組前面插入元素的方法

    JavaScript數(shù)組前面插入元素的方法

    這篇文章主要介紹了JavaScript數(shù)組前面插入元素的方法,涉及javascript中unshift方法的使用技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04

最新評論