欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

一、儲(chǔ)備知識(shí)

在我們?cè)陧?xiàng)目中一般會(huì)遇見(jiàn)過(guò)這樣的兩種定時(shí)器,第一種是setTimeOut,第二種是setInterval,這兩種定時(shí)器有如下的區(qū)別:

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

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

舉一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明一下:

<!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>

這個(gè)運(yùn)行后的結(jié)果是彈出了一次對(duì)話框,然后在控制臺(tái)可以看到每1秒鐘會(huì)向其中輸出demo字樣

二、定時(shí)器原理初識(shí)

那么問(wèn)題來(lái)了,如下的代碼運(yùn)行的時(shí)候會(huì)出現(xiàn)什么情況呢?

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

是先執(zhí)行alert("測(cè)試"),還是先執(zhí)行alert("定時(shí)器")呢,那么我們就來(lái)運(yùn)行一下吧!

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

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

三、瀏覽器的多線程

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

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

以下面的代碼我們來(lái)分析一下:

setTimeout("alert('定時(shí)器!')",0);
alert("測(cè)試")

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

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

 好的我們將上面的代碼改寫(xiě)成這樣,然后我們?cè)賮?lái)看看效果:

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

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

    這里有幾個(gè)知識(shí)點(diǎn):

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

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

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

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

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

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

四、setInterval的使用

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

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

五、定時(shí)器的可靠性

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

如下所示:

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

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

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

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

六、定時(shí)器的妙用

 定時(shí)器在項(xiàng)目中除了可以作為定時(shí)的作用外還可以用來(lái)做耗時(shí)代碼的優(yōu)化:

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

七、定時(shí)器使用注意事項(xiàng)

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

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

相關(guān)文章

  • JavaScript 異步調(diào)用

    JavaScript 異步調(diào)用

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

    詳解Typescript中奇怪的賦值操作

    這篇文章主要來(lái)和大家討論一下typescript中一些奇怪的賦值語(yǔ)句,探索其背后原因,更深入的了解typescript作為一個(gè)結(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個(gè)非常實(shí)用的JavaScript代碼片段

    15個(gè)非常實(shí)用的JavaScript代碼片段

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論