setTimeout veya setInterval?


763

Anlayabildiğim kadarıyla, bu iki javascript parçası aynı şekilde davranıyor:

Seçenek A:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

Seçenek B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

SetTimeout ve setInterval kullanma arasında fark var mı ?


6
JS'deki zamanlayıcıların nasıl çalıştığı hakkında iyi ayrıntılar istiyorsanız, John Resig bu konuda iyi bir makale yazdı
Rafael

9
Ayrıca setTimeout'un yayılmasını sağlamak için ekstra bir kod satırı gerektirdiği, bu da bir bakım sorunu olmanın dezavantajı olan ancak dönemi kolayca değiştirmenize izin vermenin yararı olan açık bir fark var
annakata


4
@JapanPro teşekkürler ama gerçekten zaman aşımları çalışırken bir sorun yoktu. Bu yazı farkın ne olduğu ve hangisinin kullanılması gerektiğiyle ilgiliydi.
Damovisa

Yanıtlar:


670

Esasen aynı şeyi yapmaya çalışırlar, ancak setIntervalyaklaşım 1000ms beklediğinden, işlevi çalıştırdığından ve başka bir zaman aşımı ayarladığından setTimeoutyaklaşımdan daha doğru olacaktır setTimeout. Bu nedenle bekleme süresi aslında 1000 ms'den biraz fazladır (veya işlevinizin yürütülmesi uzun zaman alıyorsa çok daha fazladır).

Biri olduğunu düşünmelerine rağmen setIntervalçalıştırır tam olarak her 1000 ms, o nota önemlidir setIntervalJavaScript çok parçacıklı dil olmadığı için, ayrıca gecikme hangi vasıta olduğunu - aralık olacak - çalıştıran komut diğer bölümleri varsa bitmesini beklemek.

Gelen bu Fiddle , açıkça aralık (script yapmaya çalışıyor) ikinci neredeyse 1 çağrı / neredeyse her zaman ise zaman aşımı, geride düşecek görebilirsiniz. Üstteki hız değişkenini 20 gibi küçük bir şeye değiştirirseniz (yani saniyede 50 kez çalışmaya çalışacaktır), aralık asla saniyede ortalama 50 tekrarlamaya ulaşmayacaktır.

Gecikme neredeyse her zaman ihmal edilebilir, ancak gerçekten hassas bir şey programlıyorsanız, kendi kendini ayarlayan bir zamanlayıcı için gitmelisiniz (esas olarak, oluşturulduğu gecikme için kendini sürekli olarak ayarlayan zaman aşımı tabanlı bir zamanlayıcıdır)


4
Andy'nin de benzer bir önerisi vardı. Varsayımsal olarak, yöntemin yürütülmesi 1000 ms'den fazla sürerse, aynı anda birden fazla çalıştırabileceğiniz anlamına mı gelir?
Damovisa

14
Teorik olarak, evet. Uygulamada, Javascript çoklu okuma özelliğini desteklemediğinden hayır. Kodunuz 1000 ms'den uzun sürerse, tarayıcıyı dondurur.
Kamiel Wanrooij

61
Teknik olarak, kod , zamanlayıcının çözünürlüğüne ve diğer kodun zaten yürütülüp yürütülmediğine bağlı olduğundan tam olarak her 1000 ms'de bir yürütülmez. Demek istediğin hala duruyor.
Matthew Crumley

10
setInterval iki şekilde farklıdır, 1. setInterval özyinelemeli değildir ve setInterval, setTimeout ilk kez herhangi bir gecikme olmadan çağrılırken işlevinizi ilk kez söylenen süreden sonra arayacak ve bundan sonra söylenen süreden sonra tekrar arayacaktır. İlk infazdan sonra neredeyse aynı şekilde çalışırlar.
Hafiz

5
Fark, setTimeout'un kendini tekrarlamamasıdır. Bir komut dosyasını belirli bir süre sonra, ancak yalnızca bir kez çalıştırmanıza izin verir. Öte yandan setInterval, clearTimeout () ile durdurulana kadar bu komut dosyasını tekrarlar.
Leander

648

Fark var mı?

Evet. Bir Timeout, setTimeout () çağrıldıktan sonra belirli bir süre çalıştırır; bir Aralık, önceki aralık tetiklendikten sonra belirli bir süre çalıştırır.

DoStuff () işlevinizin yürütülmesi biraz zaman alıyorsa, farkı göreceksiniz. Örneğin, setTimeout / setInterval ile bir çağrıyı temsil edersek ., zaman aşımı / aralığının *ve ile JavaScript kodunun çalıştırılmasını [-----]tetiklersek, zaman çizelgeleri şöyle görünür:

Timeout:

.    *  .    *  .    *  .    *  .
     [--]    [--]    [--]    [--]

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]

Bir sonraki zorluk, JavaScript zaten bir şey yapmakla meşgulken (önceki bir aralığı işlemek gibi) bir aralık tetiklenmesidir. Bu durumda, aralık hatırlanır ve önceki işleyici bittiğinde ve denetimi tarayıcıya geri döndürdüğünde gerçekleşir. Örneğin, bazen kısa ([-]) ve bazen uzun ([-----]) bir doStuff () işlemi için:

.    *    *        *        *    *
     [-]  [-----][-][-----][-][-]  [-]

• kodunu hemen yürütemeyen ve bunun yerine beklemede olan bir aralık tetiklemeyi temsil eder.

Bu yüzden aralıklar programa geri dönmek için 'yakalamaya' çalışır. Ancak, birbiri üzerinde sıraya girmezler: aralık başına yalnızca bir yürütme olabilir. (Hepsi sıraya alınırsa, tarayıcı sürekli genişleyen olağanüstü yürütme listesiyle bırakılır!)

.    *            x            x
     [------][------][------][------]

x, yürütülemeyen veya beklemede yapılamayan bir aralık tetiklemesini temsil eder, bunun yerine atılır.

DoStuff () işlevinizin yürütülmesi alışılmış şekilde ayarlanan aralıktan daha uzun sürerse, tarayıcı hizmet vermeye çalışırken% 100 CPU tüketir ve daha az yanıt verebilir.

Hangisini kullanıyorsunuz ve neden?

Zincirleme Zaman Aşımı tarayıcıya garantili bir boş zaman aralığı sağlar; Aralık, çalıştırdığı işlevin, tarayıcı kullanıcı arabirimi kullanılabilirliği pahasına, planlanan zamanlarına mümkün olduğunca yakın yürütülmesini sağlamaya çalışır.

Zincirleme zaman aşımları sayfa yüklenirken her zaman gerçekleşecek olan animasyonlar için daha nazikken, bir kerelik animasyonlar için olabildiğince düzgün olmasını istediğim bir aralık düşünürdüm. Daha az zorlu kullanımlar için (her 30 saniyede bir ateş eden önemsiz bir güncelleyici gibi), ikisini de güvenle kullanabilirsiniz.

Tarayıcı uyumluluğu açısından, setTimeout setInterval'dan önce gelir, ancak bugün karşılaşacağınız tüm tarayıcılar her ikisini de destekler. Uzun yıllar boyunca son straggler WinMo <6.5 IE Mobil oldu, ama umarım bu da şimdi geride.


Ancak Aralık ve Zaman Aşımı arasındaki seçimin nedeni, örneğin WebOS veya JIL gibi tarayıcı olmayan platformlarda bile geçerli mi?
Vid L

2
Anonim işlevlerde zincirleme zaman aşımları yapmanın güzel bir yolu: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10)
Justin Meyer

1
Tarayıcı uyumluluğu açısından, tüm tarayıcılar her iki yöntemi de sağlamasına rağmen, performansları farklıdır.
unigg

"Ama sonra da kullandığınız hiçbir şeyi desteklemiyor olması" çok doğru
Temel

1
setTimeout ("schedule ()", 0) kullanılarak krom projesi ile tambur makinesi ; Dolayısıyla, krom veya kaynak eksikliği için arka plan sekmesi olduğunda tarayıcının gereksiz yığını olmaz.
Elliot Yap

91

setInterval ()

setInterval()aralığa ulaşıldığında belirli bir komut dosyasını tekrar tekrar çalıştırabilme özelliğine sahip bir zaman aralığı tabanlı kod yürütme yöntemidir. O gerektiğini değil o zamandan beri, bu döngü yapmak için komut yazarı tarafından geri arama işlevi içine iç içe varsayılan olarak döngüler . Aramadığınız sürece aralıkta ateş etmeye devam edecektir clearInterval().

Animasyonlar için veya bir saat işaretinde kod döngüsü yapmak istiyorsanız, tuşunu kullanın setInterval().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);

setTimeout ()

setTimeout()aralığa ulaşıldığında bir komut dosyasını yalnızca bir kez çalıştıracak zaman tabanlı bir kod yürütme yöntemidir . Bu olacak değil sen yerleştirerek döngü senaryoyu onu dişli sürece tekrar tekrar setTimeout()yayınlanmasının çağırır fonksiyonunun amacı, içini. Döngüye yönelikse, aramadığınız sürece aralıkta ateş etmeye devam edecektir clearTimeout().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);

Belirli bir süre sonra bir şey olmasını istiyorsanız o zaman kullanın setTimeout(). Bunun nedeni, belirtilen aralığa ulaşıldığında yalnızca bir kez yürütmesidir.


6
Güzel bir açıklama ancak OP'nin OP'nin sağladığı örneklerde temel farkı anladığını unutmayın. Özellikle, OP setTimeout()örneğinde, özyinelemelisetTimeout() olarak adlandırılırken buna izin verilmediğini unutmayın. setInterval()
DavidRR

44

SetInterval, kodunuzun ileride yürütülmesini iptal etmeyi kolaylaştırır. SetTimeout kullanıyorsanız, daha sonra iptal etmek istemeniz durumunda zamanlayıcı kimliğini takip etmelisiniz.

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

karşı

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);

35
SetInterval durumunda zamanlayıcı kimliğini nasıl takip etmediğinizi göremiyorum. Sadece fonksiyondan çekildi.
Kekoa

1
İle başka bir seçenek setTimeoutkimliğini kaydetmek yerine ifsadece bir koşul doğru olduğunda bir sonraki zaman aşımını ayarlamak için bir ifade ekleyin .
nnnnnn

7
Kekoa, iyi bir nokta. Ancak aralık kimliğini yalnızca bir kez kaydetmeniz gerekir. Zaman aşımı kimliği muhtemelen her çağrıda değişiyor, bu nedenle bu değişiklikleri takip etmeniz gerekiyor . Zaman aşımını temizlemek isteyen kodun bir şekilde bu değişkenin geçerli değerine erişimi olmalıdır. Ayrıca doStuff, kimlik geçersiz olduğu için çalışırken zaman aşımını temizlemek imkansızdır . Ancak, zaman aşımı kimliklerini kaydetmek gerçekten gerekli değildir. Bunun yerine aramayı durdurabilirsiniz setTimeout.
Robert

4
Deneyimlerime göre, çoğu zaman setTimeout'u kullanırken bile iptal etmek istersiniz. Bir sonraki çağrının gerçekleşmesinden önce iptal etmek istediğiniz sürenin% 99'u , bir sonraki çağrının bitmesinden sonra değil .
Kamiel Wanrooij

23

setTimeoutZaman aşımını iptal etmek istiyorsanız yöntemi kullanmayı daha kolay buluyorum :

function myTimeoutFunction() {
   doStuff();
   if (stillrunning) {
      setTimeout(myTimeoutFunction, 1000);
   }
}

myTimeoutFunction();

Ayrıca, işlevde bir şeyler ters giderse, hatayı her saniye tekrarlamak yerine, ilk seferde tekrarlamayı durduracaktır.


20

Çok fark amaçlarında.

setInterval()
   -> executes a function, over and over again, at specified time intervals  

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds

Bu kadar basit

Burada daha ayrıntılı ayrıntılar http://javascript.info/tutorial/settimeout-setinterval


7
Güzel özlü açıklama, ancak OP'nin OP'nin sağladığı örneklerde temel farkı anladığını unutmayın. Özellikle, OP setTimeout()örneğinde, özyinelemelisetTimeout() olarak adlandırılırken buna izin verilmediğini unutmayın. setInterval()
DavidRR

14

SetInterval içinde bazı işlevleri çalıştırdığınızda, zaman aşımından daha uzun süre çalışır-> tarayıcı sıkışmış olacaktır.

- Örneğin, doStuff () 1500 saniye sürer. çalıştırılacak ve şunları yapacaksınız: setInterval (doStuff, 1000);
1) Tarayıcı , 1.5 saniye süren doStuff () komutunu çalıştırır . idam edilecek;
2) ~ 1 saniye sonra tekrar doStuff () komutunu çalıştırmayı dener . Ancak önceki doStuff () hala yürütülür-> böylece tarayıcı bu çalıştırmayı kuyruğa ekler (ilk bittikten sonra çalıştırmak için).
3,4, ..) Sonraki yinelemeler için yürütme kuyruğuna aynı ekleme, ancak öncekinden doStuff () hala devam ediyor ...
Sonuç olarak - tarayıcı sıkıştı.

Bu davranışı önlemek için, setInterval öykünmek için setTimeout içinde setTimeout çalıştırmaktır .
SetTimeout aramaları arasındaki zaman aşımlarını düzeltmek için, JavaScript'in setInterval tekniğine göre kendi kendini düzelten bir alternatif kullanabilirsiniz .


1
Bu cevapta neden kimsenin değer bulamadığını bilmiyorum!
Randika Vishman


9

Kodunuzun farklı yürütme amaçları olacaktır ve çevrimiçi oyunlar gibi bazı projelerde kabul edilemez. İlk olarak, kodunuzun aynı amaçlarla çalışmasını sağlamak için ne yapmalısınız? "MyTimeoutFunction" ifadesini şu şekilde değiştirmeniz gerekir:

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()

Bu değişiklikten sonra eşit olacaktır

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Ancak, hala istikrarlı bir sonuç elde edemezsiniz, çünkü JS tek iş parçacıklıdır. Şimdilik, JS iş parçacığı bir şeyle meşgul olacaksa, geri arama işlevinizi yürütemez ve yürütme 2-3 ms ertelenir. Saniyede 60 yürütme var mı ve rastgele 1-3 sn gecikme olduğunda, kesinlikle kabul edilemez (bir dakika sonra 7200 msn gecikme olacak) ve böyle bir şey kullanmanızı tavsiye edebilirim:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

Bu kod, kararlı yürütme süresini garanti eder. İş parçacığı bile meşgul olacak ve kodunuz 1005 saniye sonra yürütülecek, bir dahaki sefere 995 msn için zaman aşımı olacak ve sonuç kararlı olacaktır.


7

Basit bir test yaptım setInterval(func, milisec) , çünkü fonksiyon süresi tüketimi aralık süresinden daha büyük olduğunda ne olacağını merak ettim.

setIntervalolacak genellikle hemen sonra bir sonraki iterasyon planlamak başlamasından önceki yinelemenin işlevi halen devam etmektedir sürece . Eğer öyleyse, setIntervalfonksiyon bitene kadar bekleyecektir. En kısa sürede, fonksiyon hemen tekrar başlatılır - programa göre bir sonraki tekrarlama için bekleme yoktur (zaman aşımı olmayan koşullar altında olacağı için). Paralel yinelemelerin çalıştığı bir durum da yoktur.

Bunu Chrome v23'te test ettim. Umarım tüm modern tarayıcılarda deterministik bir uygulamadır.

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

Konsol çıkışı:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

waitFonksiyon sadece iplik engelleme yardımcısıdır - senkron ajax çağrısı tam olarak alır 2500 milisaniye sunucu tarafında işleme:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}

1
"paralel yinelemelerde durum yok" - evet, bu imkansız olmalı. İstemci tarafı JavaScript'in tek bir iş parçacığı yürütme modeli vardır, bu nedenle hiçbir şey (olay işleyicileri vb.) Aynı anda gerçekleşmez. Bu nedenle, senkron ajax çağrısı sırasında hiçbir şey olmuyor (ve tarayıcı yanıt vermiyor).
MrWhite

Tarayıcı "aralıklar" arasındaki birkaç ms'de yanıt veriyor mu? Bekleyen başka bir olay olur mu? (Testler için teşekkürler btw +1)
MrWhite

1
MDN'ye göre , işlev aralık süresinden daha uzun süre çalışabiliyorsa " tehlikeli kullanım " olarak kabul edilir . Yinelemeli setTimoutçağrı tercih edilir.
MrWhite

6

Biraz daha farklı bakmak için: setInterval, bir kodun verilen her aralıkta (yani 1000 ms veya ne kadarını belirttiğiniz) çalıştırılmasını sağlarken setTimeout, kodu çalıştıracak kadar 'bekleyeceği' süreyi ayarlar. Ve kodu çalıştırmak için ek milisaniye sürdüğü için, 1000 ms'ye kadar ekler ve böylece setTimeout tam olmayan zamanlarda (1000 ms'den fazla) tekrar çalışır.

Örneğin, zamanlayıcılar / geri sayımlar setTimeout ile yapılmaz, setInterval ile yapılır, gecikmemesini ve kodun verilen aralıkta çalışmasını sağlar.


5

Hem setInterval hem de setTimeout, yürütmeyi iptal etmek için, yani zaman aşımları tetiklenmeden önce kullanabileceğiniz bir zamanlayıcı kimliği döndürür. İptal etmek için clearInterval veya clearTimeout'u şu şekilde arayın:

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);

Ayrıca, sayfadan ayrıldığınızda veya tarayıcı penceresini kapattığınızda zaman aşımları otomatik olarak iptal edilir.


4

Aşağıdaki javascript'i çalıştırdığınızda veya bu JSFiddle'ı kontrol ettiğinizde bobince yanıtını kendiniz doğrulayabilirsiniz.

<div id="timeout"></div>
<div id="interval"></div>

var timeout = 0;
var interval = 0;

function doTimeout(){
    $('#timeout').html(timeout);
    timeout++;
    setTimeout(doTimeout, 1);
}

function doInterval(){
    $('#interval').html(interval);
    interval++;
}

$(function(){
    doTimeout();
    doInterval();
    setInterval(doInterval, 1);
});

3

Yeni öğrendiğim gibi, setTimeout bir durumda daha iyi. Ben her zaman arka planda yarım saatten fazla çalıştırmak için bırakmış setInterval kullanın. Bu sekmeye geri döndüğümde, slayt gösterisi (kodun kullanıldığı), olması gereken her 5 saniyede bir yerine çok hızlı değişiyordu. Daha fazla test ettiğimde ve tarayıcının hatası olup olmadığı önemli değil, çünkü tekrar olur, çünkü setTimeout ile bu durum tamamen imkansızdır.


Aradığınız işlevin içinde setInterval'ı çağırmışsınız gibi geliyor. SetTimeout ile bu şekilde döngü yaparsınız, ancak setInterval ile her çağrıldığında tamamen yeni bir döngü oluşturursunuz.
Stephen R


2

Daha önce söylenenleri eklemeniz yeterli ancak kodun setTimeout sürümü de bu kodun Maximum call stack sizeçalışmasını engelleyecek. Yinelemeli işlevin durması için temel durum olmadığından, sonsuza kadar çalıştıramazsınız .


Bunun doğru olduğunu düşünmüyorum. Buraya bakın stackoverflow.com/questions/8058612/…
Kevin Wheeler

-1

Ve setInterval (ifade, süre) arasındaki en genel fark,

setTimeout () yöntemi yalnızca ONCE ve belirtilen süreden sonra gelen ifadeyi yürütür.

Ancak,

setInterval (), belirtilen her süreden sonra ifadeyi INFINITE-LOOP içinde yürütür.


-5

Bence SetIntervalve SetTimeoutfarklılar. SetIntervalbloğu ayarlanan zamana göre SetTimeoutyürütür, kod bloğunu bir kez yürütür.

Zaman aşımı geri sayımı saniyelerinden sonra şu kod kümesini deneyin:

setInterval(function(e){
    alert('Ugbana Kelvin');
}, 2000);

ve sonra dene

setTimeout(function(e){
    alert('Ugbana Kelvin');
}, 2000);

Farklılıkları kendiniz görebilirsiniz.


Bu soruya cevap vermiyor. settimeout (), setinterval ile aynı sonucu vermek için yinelemeli olarak kullanılabilir. Soru, bu iki seçeneğin performansı hakkındaydı.
Tomas Gonzalez
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.