目錄
1、setTimeout()
2,setInterval()
3,clearTimeOut(),clearInterval()
4,运行机制
5, setTimeout(f,0)
6 ,正常任务与微任务
首頁 web前端 js教程 js中定時器函數的使用方法介紹(附程式碼)

js中定時器函數的使用方法介紹(附程式碼)

Aug 22, 2018 pm 02:41 PM
定時器

這篇文章帶給大家的內容是關於js中定時器函數的使用方法介紹(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

1、setTimeout()

setTimeout函數用來指定某個函數或某段程式碼,在多少毫秒之後執行。它傳回一個整數,表示定時器的編號,以後可以用來取消這個定時器。

var timerId = setTimeout(func|code, delay)
登入後複製

上面程式碼中,setTimeout函數接受兩個參數,第一個參數func|code是將要延遲執行的函數名稱或一段程式碼,第二個參數delay是延遲執行的毫秒數。

要注意的是,延遲執行的程式碼必須以字串的形式,放入setTimeout,因為引擎內部使用eval函數,將字串轉為程式碼。如果延遲執行的是函數,則可以直接將函數名,放入setTimeout。一方面eval函數有安全疑慮,另一方面為了方便JavaScript引擎優化程式碼,setTimeout方法一般總是採用函數名稱的形式,就像下面這樣。

function f(){ 
 console.log(2);
}
setTimeout(f,1000);
// 或者
setTimeout(function (){
console.log(2)
},1000);
登入後複製

如果省略setTimeout的第二個參數,則該參數預設為0。

除了前兩個參數,setTimeout還允許增加更多的參數。它們將被傳入推遲執行的函數(回呼函數)。

setTimeout(function(a,b){  
console.log(a+b);
},1000,1,1);
登入後複製

上面程式碼中,setTimeout共有4個參數。最後那兩個參數,將在1000毫秒之後回呼函數執行時,作為回呼函數的參數。

IE9.0及以下版本,只允許setTimeout有兩個參數,不支援更多的參數。這時有三種解決方法。第一種是在匿名函數裡面,讓回呼函數帶參數運行,再把匿名函數輸入setTimeout。

setTimeout(function() {
  myFunc("one","two", "three");
}, 1000);
登入後複製

上面程式碼中,myFunc是真正要延遲執行的函數,有三個參數。如果直接放入setTimeout,低版本的IE不能帶參數,所以可以放在一個匿名函數。

第二種解決方法是使用bind方法,把多餘的參數綁定在回呼函數上面,產生一個新的函數輸入setTimeout。

setTimeout(function(arg1){}.bind(undefined, 10), 1000);
登入後複製

上面程式碼中,bind方法第一個參數是undefined,表示將原函數的this綁定全域作用域,第二個參數是要傳入原函數的參數。它運行後會返回一個新函數,該函數不帶參數。

第三種解決方法是自訂setTimeout,使用apply方法將參數輸入回呼函數。

<!--[if lte IE 9]>
<script>(function(f){
window.setTimeout =f(window.setTimeout);
window.setInterval =f(window.setInterval);
})(function(f){
return function(c,t){
var a=[].slice.call(arguments,2);
returnf(function(){
c.apply(this,a)},t)}});
</script>
<![endif]-->
登入後複製

除了參數問題,setTimeout還有一個需要注意的地方:如果被setTimeout延遲執行的回呼函數是某個物件的方法,那麼該方法中的this關鍵字將指向全域環境,而不是定義時所在的那個物件。

var x = 1;
var o = { 
 x: 2,  y: function(){
    console.log(this.x);
  }
};
setTimeout(o.y,1000);
登入後複製

輸出結果: 1

上面程式碼輸出的是1,而不是2,這表示o.y的this所指向的已經不是o,而是全域環境了。

再看一個不容易發現錯誤的例子。

function User(login) {
  this.login = login;
  this.sayHi = function(){
    console.log(this.login);
  }
}
var user = new User(&#39;John&#39;);
setTimeout(user.sayHi, 1000);
登入後複製

上面程式碼只會顯示undefined,因為等到user.sayHi執行時,它是在全域物件中執行,所以this.login取不到值。

為了防止這個問題,一個解決方法是將user.sayHi放在函數中執行。

setTimeout(function() {
  user.sayHi();
}, 1000);
登入後複製

上面程式碼中,sayHi是在user作用域內執行,而不是在全域作用域內執行,所以能夠顯示正確的值。

另一種解決方法是,使用bind方法,將綁定sayHi綁定在user上面。

setTimeout(user.sayHi.bind(user), 1000);
登入後複製

HTML 5標準規定,setTimeout的最短時間間隔是4毫秒。為了節電,對於那些不處於目前視窗的頁面,瀏覽器會將時間間隔擴大到1000毫秒。另外,如果筆記型電腦處於電池供電狀態,Chrome和IE 9以上的版本,會將時間間隔切換到系統計時器,大約是15.6毫秒。

2,setInterval()

setInterval函數的用法與setTimeout完全一致,差異僅在於setInterval指定某個任務每隔一段時間就執行一次,也就不是無限次的定時執行。

<input type="button" onclick="clearInterval(timer)"value="stop">
<script>
  var i = 1  
var timer = setInterval(function(){
    console.log(2);
  }, 1000);
</script>
登入後複製

上面程式碼表示每隔1000毫秒就輸出一個2,直到使用者點擊了停止按鈕。

與setTimeout一樣,除了前兩個參數,setInterval方法還可以接受更多的參數,它們會傳入回呼函數,以下是一個例子。

function f(){
  for (var i=0;i<arguments.length;i++){
    console.log(arguments[i]);
  }
}
setInterval(f, 1000, "Hello World");
登入後複製

如果網頁不在瀏覽器的目前視窗(或tab),許多瀏覽器限制setInteral指定的重複執行的任務最多每秒執行一次。

下面是一個透過setInterval方法實作網頁動畫的範例。

var p = document.getElementById(&#39;somep&#39;);
var opacity = 1;
var fader = setInterval(function() 
{  opacity -= 0.1;
  if (opacity >= 0) {
    p.style.opacity = opacity;
  } else {
    clearInterval(fader);
  }}, 100);
登入後複製

上面程式碼每隔100毫秒,設定一次p元素的透明度,直到其完全透明為止。

setInterval的常見用途是實作輪詢。下面是一個輪詢URL的Hash值是否發生變化的例子。

var hash = window.location.hash;
var hashWatcher = setInterval(function() {
  if (window.location.hash != hash) {
    updatePage(); 
 }}, 1000);
登入後複製

setInterval指定的是「開始執行」之間的間隔,不考慮每次任務執行本身所消耗的時間。因此實際上,兩次執行之間的間隔會小於指定的時間。例如,setInterval指定每100ms執行一次,每次執行需要5ms,那麼第一次執行結束後95毫秒,第二次執行就會開始。如果某次執行耗時特別長,例如需要105毫秒,那麼它結束後,下次執行就會立即開始。

为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。

var i = 1;
var timer = setTimeout(function() {
  alert(i++);
  timer = setTimeout(arguments.callee,2000);
}, 2000);
登入後複製

上面代码可以确保,下一个对话框总是在关闭上一个对话框之后2000毫秒弹出。

根据这种思路,可以自己部署一个函数,实现间隔时间确定的setInterval的效果。

function interval(func, wait){
  var interv = function(){
    func.call(null);
    setTimeout(interv,wait);
  };
  setTimeout(interv,wait);
}interval(function(){
  console.log(2);
},1000);
登入後複製

上面代码部署了一个interval函数,用循环调用setTimeout模拟了setInterval。

HTML5标准规定,setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒。

3,clearTimeOut(),clearInterval()

setTimeout和setInterval函数,都返回一个表示计数器编号的整数值,将该整数传入clearTimeout和clearInterval函数,就可以取消对应的定时器。

var id1 = setTimeout(f,1000);
var id2 = setInterval(f,1000);
clearTimeout(id1);
clearInterval(id2);
登入後複製

setTimeout和setInterval返回的整数值是连续的,也就是说,第二个setTimeout方法返回的整数值,将比第一个的整数值大1。利用这一点,可以写一个函数,取消当前所有的setTimeout。

(function() {
  var gid = setInterval(clearAllTimeouts,0);
  function clearAllTimeouts(){
    var id = setTimeout(function(){}, 0);
    while (id >0) {
      if (id !==gid) {
        clearTimeout(id);
      }
      id--;
    }
  }})();
登入後複製

运行上面代码后,实际上再设置任何setTimeout都无效了。

下面是一个clearTimeout实际应用的例子。有些网站会实时将用户在文本框的输入,通过Ajax方法传回服务器,jQuery的写法如下。

$(&#39;textarea&#39;).on(&#39;keydown&#39;, ajaxAction);
登入後複製

这样写有一个很大的缺点,就是如果用户连续击键,就会连续触发keydown事件,造成大量的Ajax通信。这是不必要的,而且很可能会发生性能问题。正确的做法应该是,设置一个门槛值,表示两次Ajax通信的最小间隔时间。如果在设定的时间内,发生新的keydown事件,则不触发Ajax通信,并且重新开始计时。如果过了指定时间,没有发生新的keydown事件,将进行Ajax通信将数据发送出去。

这种做法叫做debounce(防抖动)方法,用来返回一个新函数。只有当两次触发之间的时间间隔大于事先设定的值,这个新函数才会运行实际的任务。假定两次Ajax通信的间隔不小于2500毫秒,上面的代码可以改写成下面这样。

$(&#39;textarea&#39;).on(&#39;keydown&#39;, debounce(ajaxAction, 2500))
登入後複製

利用setTimeout和clearTimeout,可以实现debounce方法,该方法用于防止某个函数在短时间内被密集调用。具体来说,debounce方法返回一个新版的该函数,这个新版函数调用后,只有在指定时间内没有新的调用,才会执行,否则就重新计时。

function debounce(fn, delay){
  var timer = null;// 声明计时器
  return function(){
    var context =this;
    var args = arguments;
    clearTimeout(timer); 
   timer = setTimeout(function(){
      fn.apply(context,args); 
   }, delay);
  };
}
登入後複製

// 用法示例

var todoChanges = _.debounce(batchLog, 1000);
Object.observe(models.todo, todoChanges);
登入後複製

现实中,最好不要设置太多个setTimeout和setInterval,它们耗费CPU。比较理想的做法是,将要推迟执行的代码都放在一个函数里,然后只对这个函数使用setTimeout或setInterval。

4,运行机制

setTimeout和setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮EventLoop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。

这意味着,setTimeout和setInterval指定的代码,必须等到本轮EventLoop的所有同步任务都执行完,再等到本轮EventLoop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。

setTimeout(someTask, 100);
veryLongTask();
登入後複製

上面代码的setTimeout,指定100毫秒以后运行一个任务。但是,如果后面的veryLongTask函数(同步任务)运行时间非常长,过了100毫秒还无法结束,那么被推迟运行的someTask就只有等着,等到veryLongTask运行结束,才轮到它执行。

这一点对于setInterval影响尤其大。

setInterval(function () {
  console.log(2);
}, 1000);
(function () {
  sleeping(3000);
})();
登入後複製

上面的第一行语句要求每隔1000毫秒,就输出一个2。但是,第二行语句需要3000毫秒才能完成,请问会发生什么结果?

结果就是等到第二行语句运行完成以后,立刻连续输出三个2,然后开始每隔1000毫秒,输出一个2。也就是说,setIntervel具有累积效应,如果某个操作特别耗时,超过了setInterval的时间间隔,排在后面的操作会被累积起来,然后在很短的时间内连续触发,这可能或造成性能问题(比如集中发出Ajax请求)。

5, setTimeout(f,0)

setTimeout的作用是将代码推迟到指定时间执行,如果指定时间为0,即setTimeout(f, 0),那么会立刻执行吗?

答案是不会。因为上一段说过,必须要等到当前脚本的同步任务和“任务队列”中已有的事件,全部处理完以后,才会执行setTimeout指定的任务。也就是说,setTimeout的真正作用是,在“消息队列”的现有消息的后面再添加一个消息,规定在指定时间执行某段代码。setTimeout添加的事件,会在下一次Event Loop执行。

setTimeout(f, 0)将第二个参数设为0,作用是让f在现有的任务(脚本的同步任务和“消息队列”指定的任务)一结束就立刻执行。也就是说,setTimeout(f, 0)的作用是,尽可能早地执行指定的任务。而并不是会立刻就执行这个任务。

setTimeout(function () {
  console.log(&#39;hello world!&#39;);
}, 0);
登入後複製

上面代码的含义是,尽可能早地显示“hello world!”。

setTimeout(f, 0)指定的任务,最早也要到下一次EventLoop才会执行。请看下面的例子。

setTimeout(function() {
  console.log("Timeout");
}, 0)
function a(x) {
  console.log("a()开始运行");
  b(x);
  console.log("a()结束运行");
}
function b(y) {
  console.log("b()开始运行");
  console.log("传入的值为" + y);
  console.log("b()结束运行");
}
console.log("当前任务开始");
a(42);
console.log("当前任务结束");
登入後複製

输出结果如下:

// 当前任务开始, a() 开始运行, b() 开始运行, 传入的值为42,b() 结束运行, a() 结束运行, 当前任务结束

上面代码说明,setTimeout(f, 0)必须要等到当前脚本的所有同步任务结束后才会执行。

即使消息队列是空的,0毫秒实际上也是达不到的。根据HTML5标准,setTimeout推迟执行的时间,最少是4毫秒。如果小于这个值,会被自动增加到4。这是为了防止多个setTimeout(f, 0)语句连续执行,造成性能问题。

另一方面,浏览器内部使用32位带符号的整数,来储存推迟执行的时间。这意味着setTimeout最多只能推迟执行2147483647毫秒(24.8天),超过这个时间会发生溢出,导致回调函数将在当前任务队列结束后立即执行,即等同于setTimeout(f, 0)的效果。

6 ,正常任务与微任务

正常情况下,JavaScript的任务是同步执行的,即执行完前一个任务,然后执行后一个任务。只有遇到异步任务的情况下,执行顺序才会改变。

这时,需要区分两种任务:正常任务(task)与微任务(microtask)。它们的区别在于,“正常任务”在下一轮EventLoop执行,“微任务”在本轮Event Loop的所有任务结束后执行。

console.log(1);
setTimeout(function() {
  console.log(2);
}, 0);
Promise.resolve().then(function() {
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);
登入後複製

输出结果如下:

// 1, 5,3,4, 2

上面代码的执行结果说明,setTimeout(fn, 0)在Promise.resolve之后执行。

这是因为setTimeout语句指定的是“正常任务”,即不会在当前的Event Loop执行。而Promise会将它的回调函数,在状态改变后的那一轮Event Loop指定为微任务。所以,3和4输出在5之后、2之前。

正常任务包括以下情况。

•   setTimeout

•   setInterval

•   setImmediate

•   I/O

•   各种事件(比如鼠标单击事件)的回调函数

微任务目前主要是process.nextTick和 Promise 这两种情况。

相关推荐:


 

以上是js中定時器函數的使用方法介紹(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何在 iPhone 相機上設定定時器 如何在 iPhone 相機上設定定時器 Apr 14, 2023 am 10:43 AM

您可以在 iPhone 相機上設定多長時間的定時器?當您在 iPhone 的相機應用程式中存取定時器選項時,您將獲得在兩種模式之間進行選擇的選項:3 秒 (3s)和10 秒 (10s)。當您手持 iPhone 時,您可以使用第一個選項從前置或後置相機快速自拍。第二個選項在場景中很有用,可以在遠處將 iPhone 安裝到三腳架上來點擊合照或自拍。如何在 iPhone 相機上設定定時器 雖然在 iPhone 相機上設定定時器是一個相當簡單的過程,但具體操作方式因所使用的 iPhone 機型而異。

如何實作Workerman文件中的定時器功能 如何實作Workerman文件中的定時器功能 Nov 08, 2023 pm 05:06 PM

如何實現Workerman文件中的定時器功能Workerman是一款強大的PHP非同步網路通訊框架,它提供了豐富的功能,其中就包括定時器功能。使用定時器可以在指定的時間間隔內執行程式碼,非常適合定時任務、輪詢等應用程式場景。接下來,我將詳細介紹如何在Workerman中實現定時器功能,並提供具體的程式碼範例。第一步:安裝Workerman首先,我們需要安裝Worker

java定時器表達式是什麼 java定時器表達式是什麼 Dec 27, 2023 pm 05:06 PM

定時器的表達式用於定義任務的執行計劃。定時器的表達式是基於「在給定的時間間隔之後執行任務」的模型。表達式通常由兩個部分組成:一個初始延遲和一個時間間隔。

如何在Java中設定每日定時任務執行的定時器? 如何在Java中設定每日定時任務執行的定時器? Dec 27, 2023 am 11:10 AM

Java定時器:如何設定每天定時執行任務?在日常的Java開發中,我們常常會遇到需要每天定時執行某個任務的需求。比如說每天凌晨1點執行資料備份任務,或是每天晚上8點發送日報郵件等等。那麼在Java中,我們可以使用定時器來實現這樣的功能。 Java提供了多種定時器的實作方式,本文將介紹基於Timer和ScheduledExecutorService兩種方式來設定

定時器的工作原理是什麼 定時器的工作原理是什麼 Aug 16, 2023 pm 02:18 PM

定時器的工作原理可分為硬體定時器和軟體定時器兩種類型。硬體定時器的工作原理是時脈訊號源提供穩定的時脈訊號作為計時器的基準。計數器從預設值開始計數,每當時脈訊號到達時計數器會增加。當計數器達到預設值時,定時器會觸發中斷訊號通知中斷控制器處理對應的中斷服務程序。在中斷服務程序中,可以執行一些預定的操作。軟體定時器的工作原理是透過程式語言或系統提供的函式庫函數或系統呼叫來實現的等等。

如何在Java中設定定時執行每月任務? 如何在Java中設定定時執行每月任務? Jan 11, 2024 pm 04:50 PM

Java定時器:如何設定每月定時執行任務?引言:在開發中,經常會遇到需要每月定時執行任務的場景,例如每月更新統計資料、定期發送報表等。 Java提供了多種定時器實作方式,本文將介紹如何使用Java定時器來實作每月定時執行任務,並提供具體的程式碼範例。一、使用Timer類實作每月定時執行任務Timer類是Java提供的最基礎的定時器類,透過它可以實現簡單的定時任務

掌握Go語言文件中的time.NewTimer函數實作單次定時器 掌握Go語言文件中的time.NewTimer函數實作單次定時器 Nov 03, 2023 pm 02:19 PM

掌握Go語言文件中的time.NewTimer函數實作單次定時器,並附上具體程式碼範例。時間作為我們生活的基準,定時器是程式設計中非常常用的工具之一。在Go語言中,我們可以使用time套件來處理時間相關的操作,其中NewTimer函數可以用於建立單一計時器。本文將介紹如何使用NewTimer函數來實作一個簡單的單次定時器,並附上具體程式碼範例。在Go語言中,tim

Java定時器的多種實作方式概覽 Java定時器的多種實作方式概覽 Dec 28, 2023 pm 01:20 PM

Java定時器的幾種實作方式一覽,需要具體程式碼範例隨著電腦技術的不斷發展,程式設計師在開發應用程式時經常會遇到需要按照一定的時間間隔或在指定的時間點執行某些任務的需求。 Java作為一種廣泛使用的程式語言,提供了多種定時器的實作方式來滿足這樣的需求。本文將介紹Java中幾種常見的定時器實作方式,並提供具體的程式碼範例。 Timer類別Java中的Timer類別是最基本

See all articles