關於JavaScript定時器我的一些小理解

来源:http://www.cnblogs.com/WhiteBlade/archive/2016/04/02/5348616.html
-Advertisement-
Play Games

因為自己在平時工作中,有些功能需要用到定時器,但是定時器並不像我們表邊上看到的那樣,所以這周末我看看書查查資料,深入研究了一下JavaScript中的定時器,那麼廢話不多說,下麵進入我們今天的正題。 大家都知道JavaScript是單線程的,所以不管是定時器還是用戶的操作都是需要線上程隊列中排隊執行 ...


因為自己在平時工作中,有些功能需要用到定時器,但是定時器並不像我們表邊上看到的那樣,所以這周末我看看書查查資料,深入研究了一下JavaScript中的定時器,那麼廢話不多說,下麵進入我們今天的正題。

大家都知道JavaScript是單線程的,所以不管是定時器還是用戶的操作都是需要線上程隊列中排隊執行的。

一、定時器在執行線程隊列里的分析

為了更好的理解我還是直接寫個測試代碼來看一下,這樣分析起來更直觀一些

 1 <script type="text/javascript">
 2     var time1 = new Date().getTime();
 3     console.log("階乘函數開始時間:"+time1);
 4     function factorial(num) {
 5         if(num <= 1) {
 6             return 1;
 7         } else {
 8             return num * arguments.callee(num - 1); 
 9         }
10     }
11     var result = factorial(150);
12     console.log("階乘函數結果:"+result);
13     var time2 = new Date().getTime();
14     console.log("階乘函數結束時間1:"+time2);
15     console.log("階乘函數所用時間:"+(time2-time1));
16     setTimeout(function(){
17         var time3 = new Date().getTime();
18         factorial(10000);
19         var time4 = new Date().getTime();
20         console.log("setTimeout被執行時間:"+time3);
21         console.log("setTimeout執行的差值時間:"+(time3-time1));
22         console.log("setTimeout裡面的函數運行時間:"+(time4-time3));
23     },10);
24     setInterval(function(){
25         var time5 = new Date().getTime();
26         console.log("setInterval被執行時間:"+time5);
27         console.log("setInterval執行的差值時間:"+(time5-time1));
28     },10);
29 </script>

 在上面這段測試代碼裡面一共分為三個部分:

1.階乘計算

2.setTimeout

3.setInterval

一般人們的認知是先開始執行階乘計算,然後10ms之後會運行setTimeout裡面的內容,並且每個10ms會觸發setInterval。錶面上看是這樣,但是事實並不一定是這樣的。

下麵我貼出代碼的運行結果來逐一的分析

從運行結果可以看出,階乘函數運行需要花費15ms(多次刷新頁面可能這個時間會不一樣,所以我們先姑且認為這個階乘函數執行需要15ms)。

最開始的時候會啟動一個10ms延遲的setTimeout定時器和一個10ms間隔的setInterval定時器,由於第一階段的階乘函數需要花15ms,所以在10ms的時候,前面兩個定時器都已經過期了,由於JavaScript的單線程,這兩個定時器就需要進入線程隊列進行等待,直到第一段階乘函數運行完。

所以可以看到setTimeout在15ms的時候才開始執行,這就是我要說的定時器即使指定了時間不一定就能決定函數何時被執行。通過列印的結果可以看到setTimeout執行完需要5ms,所以在20ms的時候setInterval被開始執行。

我這裡講的是三段函數線上程隊列里的開始被執行的時間,而不是函數最後執行完的時間。

二、setTimeout和setInterval之間的區別

還是直接上代碼來進行對比

1     setTimeout(function cb(){
2         console.log("setTimeout");
3         setTimeout(cb,10);
4     },10);
5     setInterval(function(){
6         console.log("setInterval");
7     },10);

 上面的代碼看上去功能似乎是一樣的,實際上兩者是有區別的,在setTimeout里要等裡面的函數執行完(也就是前一個callback)再延遲10ms才可以再次執行回調函數,而setInterval是每隔10ms就會去執行函數裡面的內容,而不去管上一個是否執行完。這就是兩者之間的區別。

三、定時器延遲時間的可靠性

看了我第一部分貼出的運行結果之後,細心的人可能會發現我列印的定時器延遲會有1-2ms的偏差,就是下麵我要看的延遲時間可靠性的問題了

廢話不多說直接上測試代碼(為了測試效果這裡我極端一點把延遲時間設置為1ms,這樣數據結果會更加明顯一點)

1     var time1 = new Date().getTime();
2     setInterval(function(){
3         var time2 = new Date().getTime();
4         console.log("setInterval執行的差值時間:"+(time2-time1));
5     },1);

 常理上來講運行的結果應該是1 2 3 4 5 6 8 9 ...

但是實際的運行結果如下:

可以看到平均的延遲時間大概在5ms左右,我是拿chrome瀏覽器測試的,據說不同的系統下不同的瀏覽器這個平均的時間都不一樣,如果愛鑽牛角尖的小伙伴可以去嘗試一下,這裡就不深入展開了.

所以說定時器的延遲時間不宜設置過小,因為太小的話可能根本也達不到你想要的效果(不排除一些真可以控制在1ms左右的牛逼瀏覽器),而且根據設備硬體或者瀏覽器的不同可能延遲時間也會有少量的誤差

四、定時器的小妙用

有人會說定時器能有什麼妙用,無外乎就是在手機翻轉屏的時候延遲幾秒獲取設備寬度等等。

我想說的不是這些而是利用定時器來提高性能的辦法。

首先我們來模擬一個js要動態創建十萬個DOM節點的場景,這種情況瀏覽器會花費大量的時間來執行,從而阻塞了其他代碼的執行。這時如果我們使用定時器把這十萬個DOM打散分成多個部分,這樣一下就好了很多。

五、合理管理定時器

大家都知道定時器,用完之後需要清除,如果不清楚同時多個定時器在一個頁面上跑,會損耗性能讓頁面瀏覽起來有卡頓感,尤其是定時器在動畫裡面的應用,想象一下,如果製作一個動畫效果裡面用了許多定時器,並且多個定時器同時運行,那麼有可能就會出現本來後面要執行的一個動畫效果在前面就被提前執行了,這是我們不想看到的。

所以我們就要根據情況對定時器做一個合理的管理,還是拿做動畫為例,

1.動畫肯定要保持同一時間只執行一個定時器;

2.並且自己可以靈活的控制定時器的開啟和關閉。

在網上可以找到管理定時器的示例代碼,大家可以參考一下:

 1     var timers = {
 2         timerID : 0,  
 3         timers : [],     
 4         add : function (fn) {
 5             this.timers.push(fn);
 6         },
 7         start : function (){
 8             if(this.timerID) return;
 9             (function runNext(){
10                 if(timers.timers.length>0){
11                     for(var i=0;i<timers.timers.length;i++){
12                         if(timers.timers[i]() === false){
13                             timers.timers.splice(i,1);
14                             i--;
15                         }
16                     }
17                     timers.timerID = setTimeout(runNext,10);
18                 }
19             })();
20         },
21         stop : function(){
22             clearTimeout(this.timerID);
23             this.timerID = 0;
24         }
25     };
View Code

 其實管理的核心還是我上面提到的兩條。

總結

1.如果無法立即執行定時器,定時器會進入線程隊列當中排隊,等待下一個可執行的時間點,所以說定時器有些時候可能要比設定的時間要長,但是不會比設定的時間少的;

2. setTimeout和setInterval在被觸發的定義上是有很大區別的;

3.定時器的延遲時間不宜設置過小;

4.利用定時器可以分解大量操作的代碼

5.合理管理頁面中的定時器

祝大家清明小長假快樂!(其實也就比平時周末多一天而已)

感謝大家的觀看,有什麼分析的不對的地方歡迎大家批評指出,如果喜歡本文,請點擊右下角的推薦哦~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 效果: 需求和分析: 1.點擊TreeView中的節點,Listview中顯示相應的電視節目,其中節目的信息都儲存在xml文件中(IO的應用) 2.在“所有電臺”中選中節點右擊可進行添加到“我的電臺”,同時在”我的電臺“也可進行刪除,在你退出後,系統會把你選擇的”我的電臺“中的記錄記錄,在你再次打開 ...
  • 不談抽象類可以有實現等語法糖的問題,本文主要講在語義層面抽象類和介面的本質區別、以及使用以及選擇。 一、介紹 抽象類,首先是個類,類是對現實世界中對象的建模模型,抽象類是對類整體的抽象描述,包含方法,以及屬性。介面是對類某特性行為的抽象。 對抽象類的繼承才是Is-A的關係,對介面的實現,則是“有沒有 ...
  • 繼承是Is-A的關係。曾經看到有人為了復用而使用了繼承:有一個Base類,裡面寫了很多Common的方法,很多類繼承自這個類,這種做飯就是把Has-A用Is-A來實現的。 繼承的概念是說一個類是另一個類的特化。 Liskov替換原則:派生類必須能夠通過基類的介面而被使用,且使用者無需瞭解兩者之間的差 ...
  • × 目錄 [1]定義 [2]過渡屬性 [3]持續時間[4]延遲時間[5]時間函數[6]多值[7]階段[8]觸發[9]API 前面的話 通過過渡transition,可以讓web前端開發人員不需要javascript就可以實現簡單的動畫交互效果。過渡屬性看似簡單,但實際上它有很多需要註意的細節和容易混 ...
  • 一:純css+html的手風琴效果 這種用css寫的手風琴比較簡單,主要是應用到css中的,transition屬性。 代碼如下: 二:純js+html製作手風琴 這個手風琴出現一個問題,就是單獨移動每個li時,沒問題,但是當移動很快時,最右邊的li出現空隙。我感覺是定時器的問 題,就是當每個li還 ...
  • 一、六中數據類型: 二、運算符和表達式 七種運算符 三、程式控制語句 註:do-while迴圈至少執行一次迴圈體;break語句可以跳出迴圈語句;continue語句可以跳過迴圈內剩餘的語句進入下一次迴圈;label語句用於為語句添加標號 ...
  • basket.js 源碼分析 一、前言 basket.js 可以用來載入js腳本並且保存到 LocalStorage 上,使我們可以更加精準地控制緩存,即使是在 http 緩存過期之後也可以使用。因此可以使我們防止不必要的重新請求 js 腳本,提升網站載入速度。 可以到 basket.js 的 "G ...
  • 【前面的話】DOM全稱是Document Object Model,即文檔對象模型。我們常說的html文檔其實就是一個DOM樹,DOM操作就是在記憶體中找到DOM樹上我們想要的DOM對象,對它的屬性進行修改,然後渲染引擎會把修改的結果重新繪製在界面上。DOM裡面涵蓋的知識點還是很多的,尤其是到後來要兼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...