今天介紹js重複定時器,前段時間在一個項目羣裏看到有人問,爲了解決業務需求須要定義多個定時器來控制事件驅動,我就把本身在一本書上學到的重複定時器一點小知識分享出來,有須要的能夠了解了解。javascript
每一個瀏覽器窗口、標籤頁或者frame都有其各自的代碼執行隊列。這意味着,進行跨frame或者跨窗口的定時調用,當代碼同時執行的時候可能會致使競爭條件。不管什麼時候須要用到這種通訊類型,最好是在接收frame或者窗口中建立一個定時器來執行代碼。java
使用setTimeout()和setInterval()建立的定時器能夠實如今指定的時間間隔執行程序,可是這也只是表面上看去好像代碼就在精確指定的時間點上執行了。其實,javascript是運行於單線程的環境中,而定時器僅僅只是計劃代碼在將來的某個時間執行。執行時機是不能保證的,由於在頁面的生命週期裏,不一樣時間可能有其餘代碼在控制js進程。實際上,瀏覽器負責排序,指派某段代碼在某個時間點運行的優先級。瀏覽器
咱們能夠把js想象成在時間線上運行,當頁面載入時,首先執行任何包含在<script>元素內的代碼,一般是頁面生命週期後面要用到的一些簡單的函數和變量的聲明,有時候也包含一些初始數據的處理等。以後,js進程將等待更多代碼執行。當進程空閒的時候,下一個代碼會被觸發並馬上執行。因此,分析得知,js正常工做除了js主線程外,還有一個須要在進程下一次空閒時執行的代碼隊列。隨着頁面在其生命週期中的推移,代碼會按照執行順序添加入這個隊列,而後在進程空閒時儘快執行隊列中的代碼片斷。在js中沒有任何代碼是馬上執行的,只能保證是儘快執行,一旦進程空閒就馬上執行它。函數
定時器對隊列的工做方式是,當特定時間事後去將代碼插入。注意:給隊列插入添加的這部分代碼並不意味着馬上執行,而只表示它會盡快執行。指定的時間間隔表示什麼時候將定時器的代碼添加到隊列,而不是什麼時候實際執行代碼。設定了一個100ms後執行的定時器並不表明到了100ms代碼就馬上執行,它表示代碼會在100ms後被加入到隊列,此時,恰好進程處於空閒狀態則立刻就執行這段代碼,表面上看好像在指定時間內精確執行了。實際上,若是在這個時間點上,進程處於忙狀態,此時定時器代碼只能等待,等待進程空閒後立刻執行,代碼可能明顯等待更長時間才能執行。動畫
以setInterval()爲例:當業務層出現了設置重複定時器的狀況,就會引起兩個問題:(1)某些間隔會被跳過,(2)多個定時器的代碼執行之間的間隔會比預期小。由於js中有避免的一套機制,僅當未含有定時器的任何代碼實例才能添加到隊列中,致使某些間隔被跳過;本次還未執行完畢,下一次間隔時間到,就會致使定時器代碼同時出現跳過間隔且連續運行好幾回狀況。線程
這個例子中第一個定時器在205ms處添加到隊列中,可是過了300ms處才執行。當執行這個定時器代碼時,在405ms處又給隊列添加了一個副本。在下一個時間間隔即605ms處,第一個定時器代碼尚未執行完畢,此時進程忙且隊列中已經有了一個定時器代碼實例(正在執行的定時器代碼),根據js的處理機制605ms的這個時間點上的定時器代碼不會被插入到隊列中,定時器代碼跳過。結果在5ms處添加的定時器代碼執行結束以後,405ms處添加的定時器代碼就馬上執行。code
採起鏈式調用setTimeout()避免使用setInterval()的重複定時器的2個缺點.排序
(function(){ //處理中 setTimeout(arguments.callee,inerval); },interval);
這個模式鏈式調用了setTimeout(),每次執行的時候就建立一個新的定時器。第二個setTimeout()調用arguments.acllee來獲取對當前執行的函數的引用,併爲其設置另外一個定時器。這樣作的好處是,在前一個定時器代碼執行完以前,不會向隊列出插入新的定時器代碼,確保不會有任何缺失的間隔。並且,還能夠保證在下一次定時器代碼執行以前,至少要等指定的間隔,避免了連續的運行。生命週期
實現將一個div元素向右移動的動畫,當座標在200像素時中止。隊列
setTimeout(function(){ var div=document.getElementById("mydiv"); left=parseInt(div.style.left)+5; div.style.left=left+"px"; if(left<200) { setTimeout(arguments.callee,50); } },50);