[ Javascript ] JavaScript中的定時器(Timer) 是怎樣工作的!

作為入門者來說。了解JavaScript中timer的工作方式是非常重要的。通常它們的表現行為并非那么地直觀,而這是由于它們都處在一個單一線程中。讓我們先來看一看三個用來創建以及操作timer的函數。

var id = setTimeout(fn, delay); 

- 初始化一個單一的timer,這個timer將會在一定延時后去調用指定的函數。這個函數(setTimeout)將返回一個唯一的ID,我們能夠通過這個ID來取消timer。

var id = setInterval(fn, delay);
- 與setTimeout類似,僅僅只是它會持續地調用指定的函數(每次都有一個延時),直到timer被取消為止。

clearInterval(id);, clearTimeout(id);
- 接受一個timer的ID(由上述的兩個函數返回的),而且停止timer的回調事件。

要弄明確這個定時器內部是怎么工作的,有一個非常重要的概念須要被提出來:

1 定時器延遲是不準確的(guaranteed).由于全部的javascript 瀏覽器代碼僅僅有一個單線程運行,而且那些異步事件(如鼠標點擊事件,和定時器)僅僅會在出現線程空暇的時候去會運行。這有一個圖表演示。例如以下:



這里有非常多信息在這個圖中須要去理解。可是全然理解它之后。你會對javascript中異步機制有一個清楚的認識。

這個圖是一維的:

垂直方向我們用毫秒單位來標記這個時間。這個藍色的方塊代表這個正在被運行的javascript代碼。比如,這第一個被運行的javascript代碼大約花了18毫秒,這個鼠標事件塊大約花費了11毫秒,等等。

由于javascript 引擎永遠僅僅會執行一個片段的代碼在同一個時間(由于這個單線程機制),那么這時每個代碼塊將會堵塞(blocking)別的異步事件的執行。

這意味著當一個異步事件被調用(比如當一個鼠標點擊,一個定時器觸發firing,或者一個xmlhttprequest 過程完畢),它將會被增加到隊里。并延遲運行(至于詳細怎樣被入到隊列中,不同的瀏覽器有不同的實現。我們這里僅僅考慮簡單的情況)

從一開始,在第一個javasript中,有兩個定時器被初始化了: 一個10 毫秒的 setTimeout時間和一個10 毫秒的setInterval事件(這里注意,只不過初始化,亦或叫作定義)。

由于這個定時器開始的時間和位置。導致它們在第一個javascript塊完畢前就已經真正被調用(這里的調用,并不是直接運行,這里須要注意,能夠理解為僅僅是準備調用,把該回調方法增加到隊列)了。

注意,不管怎么樣(however)。定時器都不會立馬運行(由于線程沒有空暇的原因,它沒辦法直接運行)。

相反。這個被延遲的方法會被增加到隊列中,在某個能夠運行的時刻(線程空暇的時刻)運行。

另外一點,在第一個javascript塊中。我們能夠看到另一個鼠標事件被觸發了。這個javascript 回調方法被關聯到一個異步事件 (沒人知道用戶什么時候做這個動作。所以它被覺得是異步的),這個異步事件也不會立馬運行,和上面的定時器一樣。也會被增加到隊列中。

在第一個javascript 塊運行結束之后,javascript 引擎就會立馬問一個問題: 還有什么在等待被運行的代碼么? 那么這個時間,有一個鼠標事件回調和定時器回調同一時候在等待。這個瀏覽器立即挑選一個(從圖中看。是鼠標事件回調)立馬運行。這個定時器繼續等待,直到下一個可能的時刻。


注意一點:在這個這個鼠標事件處理函數正在被運行的同一時候,第一個interval 回調函數也會調用。

正如前面提到的定時器一樣,它的回調方法會被增加到隊列中。

然而。注意當這個interval再一次被調用(這個時候這個定時器的回調方法正在被運行)。那么這個時候。這個interval 的回調方法將會被刪除(drop)。

假設因為主線程須要運行非常長時間的代碼塊,導致你在隊列中增加了非常多個回調方法,那么當這個主線程結束之后,一連串的回調函數連續運行沒有間隔,直到結束。比較好的做法,是臨時讓瀏覽器歇息等待一會。讓隊列中沒有Interval回調。

我們在看到一些情況:在第三個interval 回調方法觸發的時候。inteval自身正在運行(這里應該是下在運行第二個interval沒有結束)。這里給我們展示了一個重要的信息:

interval 不會去關心當前的線程如今運行什么,它們會把自己的回調方法增加到隊列中在不論什么情況下,即使它會讓兩個間隔的回調方法之間的時間降低。

最后,在第二個interval(圖中應該是第三個,這里應為中間有一個被drop掉了)被 運行完之后,javasript引擎中已經沒有東西能夠用來運行了。

這也就是說。瀏覽器如今正在等一個新的異步事件須要去觸發(occur)。在第50毫秒的時候,再一次觸發了inteval回調。

這個時候。已經沒有東西去堵塞它的運行。所以它增加到隊列中之后就立馬運行了。

接下來,讓我們看一個樣例更好的理解setTimeout與setInterval的差別:

setTimeout(function(){/* Some long block of code... */setTimeout(arguments.callee, 10);}, 10);setInterval(function(){/* Some long block of code... */}, 10);

這兩段代碼可能在功能的實現上很的相似。不經意一看,他們是全然一樣的。

尤其是這個setTimeout代碼會在上一個回調函數運行之后至少隔10毫秒再運行一次回調方法(它可能會超過10毫秒,但不會少于10毫秒)。可是setInteval 卻會嘗試10毫秒就運行一個回調函數,不會去管上一個回調是什么時候運行的。

These two pieces of code may appear to be functionally equivalent, at first glance, but they are not. Notably the setTimeout code will always have at least a 10ms delay after the previous callback execution (it may end up being more, but never less) whereas the setInterval will attempt to execute a callback every 10ms regardless of when the last callback was executed.

這里有一些東西是我們從這里學到的,做一個總結:

1 javascript引擎只唯獨一個單線程,正在運行的異步事件會增加到隊列等待。

2 setTimeout與setInterval 是運行異步回調方法從根本上不一樣的。

3 假設一個須要馬上運行的定時器被堵塞了。它將被延遲運行。知道下一次線程空暇(那么被延遲的時間會超過定時器定義的時間)

4 interval 可能會沒有延遲的連續運行回調方法,假設主線程了運行一個足夠長的代碼(比定時的延遲長)


全部的這些都是很重要的知識對于了解javascript引擎是怎樣工作的。特別是對于大數量的回調事件發生的時候,為我們建立更好的應用代碼建立好的基礎。

----------------------------------------------------------------------------------------------------

原文出自jQuery的作者John Resig。

地址:http://ejohn.org/blog/how-javascript-timers-work/#postcomment



轉載于:https://www.cnblogs.com/claireyuancy/p/6956876.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android dropbox anr分析,Android如何分析排查ANR

釋放雙眼,帶上耳機,聽聽看~!在Android開發中,當程序發生異常時會拋出異常信息,先說下三種常見類型:列表內容KeyDispatchTimeout(谷歌default 5s,MTK平臺上是8s) –主要類型按鍵或觸摸事件在特定…

修改httpd默認端口號

Tomcat: vim /etc/httpd/conf/httpd.conf//別忘了service httpd restart Nginx: vim /etc/nginx/nginx.conf//完了之后service nginx restart 轉載于:https://www.cnblogs.com/bincoding/p/6067054.html

整合彈簧,速度和瓷磚

我喜歡 Tiles, 并且聽到了很多有關 Velocity的信息 。 它們似乎有不同的用途,并且據說很容易結合在一起,所以我決定試一試,并在Spring Web應用程序中同時使用它們。 集成實際上花費了許多小時,并且是一次真正的過山車&…

Android 軟鍵盤自動彈出和關閉

在我們寫修改信息或者搜索,修改密碼等界面的時候,用戶進入這個界面的主要目的就是輸入修改/查找 某些信息,為了用戶體驗應該自動彈出軟鍵盤而不是讓用戶主動點擊輸入框才彈出。 1.軟鍵盤的自動彈出 private void showKeyboard(){InputMethodM…

android adb殺死服務,Android app是如何殺掉的

1. adb shell kill -9 pid_of_appAMS定義了AppDeathRecipientAPP 在 attachApplication -> attachApplicationLockedAMS里會注冊 App 進程的 BinderDeath通知AppDeathRecipient adr new AppDeathRecipient(app, pid, thread);thread.asBinder().linkToDeath(adr, 0);當App進…

iOS學習筆記39-ReactiveCocoa入門

FRP,全稱為Functional Reactive Programming,是一種響應變化的編程范式,最近幾年比較火,大概的理解就像這樣: 當a的值或者b的值發生變化時,c的值會自動響應a的值或b的值變化的信號,自動更正自己…

使用密碼摘要生成器擴展JMeter

最近,我不得不處理一個帶有50,000條用戶記錄的OpenLDAP實例,并進行一些壓力測試。 JMeter是填充LDAP的最佳選擇。 但是,在我的情況下,OpenLDAP配置為不接受任何明文密碼。 因此,我無法使用通過JMeter LDAP Request采…

制造業數字化轉型核心不止是技術

一、制造業的數字化轉型意味著什么? 在當今的制造業領域,數字化轉型意味著通過集成數字技術來增強傳統的制造方法、產品和勞動力的過程。這些技術包括一系列創新,如自動化軟件、電子商務系統、傳感器、工業機器人等。 二、制造業數字化轉型的…

分類測試以減少構建時間

在繼續本文的主要內容之前,讓我們先進行一些定義。 單元測試 單元測試是小型的(測試一種用例或單元),在內存中運行(不與數據庫,消息隊列等交互),可重復且快速的測試。 對于我們的對…

android橫向展示狀態,【報Bug】Android橫屏狀態下啟動App,即使在App.vue中鎖定豎屏,但是首頁nvue中的rpx單位是按照啟動的橫豎屏狀態顯示的!...

詳細問題描述(DCloud產品不會有明顯的bug,所以你遇到的問題大都是在特定環境下才能重現的問題,請仔細描述你的環境和重現方式,否則DCloud很難排查解決你的問題)[內容]重現步驟[步驟][結果][期望]nvue首頁rpx單位能夠根據App.vue鎖定的屏幕方向…

property修飾關鍵字

修飾符按作用區分:線程安全相關,內存相關,讀寫權限相關,set和get,是否可為空, class 一.默認值 property NSArray *dataArray; 默認的是:atomic,strong(有的文章寫的居然是assign,我認為還是str…

高精度相關模板.

1 2 /*3 高精度加法.4 */5 #include<cstring>6 #include<cstdio>7 #include<iostream>8 #define MAXN 100019 using namespace std;10 int a[MAXN],b[MAXN],c[MAXN],l1,l2,l3;11 char m[MAXN],n[MAXN];12 void slove()13 {14 l3max(l1,l2);15 for(in…

5分鐘內Google App Engine上的Vaadin App

在本教程中&#xff0c;您將學習如何創建第一個Vaadin Web應用程序&#xff0c;如何在本地AppEngine開發服務器上運行它以及如何將其部署到Google App Engine基礎結構。 所有這些大約需要5到10分鐘。 是的&#xff0c;如果您安裝了必要的先決條件&#xff0c;則可以立即開始運行…

linux系統調用的封裝格式,ARM Linux系統調用的原理

ARM Linux系統調用的原理ARM Linux系統調用的原理操作系統為在用戶態運行的進程與硬件設備進行交互提供了一組接口。在應用程序和硬件之間設置一個額外層具有很多優點。首先&#xff0c;這使得編程更加容易&#xff0c;把用戶從學習硬件設備的低級編程特性中解放出來。其次&…

(延遲兩秒,跳轉相應頁面)(返回到上一個頁面并刷新)

1.setTimeout("window.location.href /moment/reason",2000);2.返回到上一個頁面并刷新 self.location document.referrer;2.1常見的幾種刷新方式 a.history.go(-1) 返回上一頁 b.location.reload() 刷新當前頁面 c.history.back() 返回上一頁2.2當…

檢索字符創 php

strstr()可以返回匹配的值 echo strstr("localhost", "os");返回ost echo substr_count("gggggs", "g"); 返回檢索匹配字符創次數 substr_replace 字串替換函數轉載于:https://www.cnblogs.com/lidepeng/p/6078064.html

android8強制將app移到sd卡,小內存手機?APP強制轉移至SD卡教程

雖然近兩年手機的機身內存越做越大&#xff0c;但是身邊總還是有些朋友在使用幾年前的手機。而面對如今海量的豐富應用&#xff0c;早年的手機中內置的存儲空間已經開始捉襟見肘。雖說對于這類機型系統通常都提供了將APP轉移至外置內存卡的功能&#xff0c;可是依然有一些頑固的…

在沒有XML的情況下測試Spring和Hibernate

我非常熱衷于Spring 3中的改進&#xff0c;這些改進最終使您能夠在IDE和編譯器的適當支持下從XML遷移到純Java配置。 它并沒有改變Spring是一個龐大的套件這一事實&#xff0c;并且有時發現您需要的東西可能需要一段時間。 圍繞Hibernate的無XML單元測試就是這樣一回事。 我知道…

Observer觀察者設計模式

Observer設計模式主要包括以下兩種對象: (1)被觀察對象:Subject,它往往包含其他對象感興趣的東西,上面例子中熱水器中就是Subject(被監視對象); (2)觀察對象:Observer,它觀察著Subject,當Subject中的某件事發生后,會告知Observer,Obersver會采取相應的行動。上面例子中顯示器和…

最小生成樹 prime zoj1586

題意&#xff1a;在n個星球&#xff0c;每2個星球之間的聯通需要依靠一個網絡適配器&#xff0c;每個星球喜歡的網絡適配器的價錢不同&#xff0c;先給你一個n&#xff0c;然后n個數&#xff0c;代表第i個星球喜愛的網絡適配器的價錢&#xff0c;然后給出一個矩陣M[i][j]代表第…