setTimeout atau setInterval?

763

Sejauh yang saya tahu, kedua javascript ini berperilaku dengan cara yang sama:

Opsi A:

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

myTimeoutFunction();

Opsi B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Apakah ada perbedaan antara menggunakan setTimeout dan setInterval ?

Damovisa
sumber
6
Jika Anda ingin beberapa detail bagus tentang cara timer di JS bekerja, John Resig menulis artikel yang bagus tentang topik ini
Rafael
9
ada juga perbedaan yang jelas bahwa setTimeout mengharuskan baris kode tambahan untuk menjaganya tetap menyebar, yang memiliki kelemahan menjadi masalah pemeliharaan tetapi manfaat membiarkan Anda mengubah periode dengan mudah
annakata
coba ini jsfiddle.net/pramendra/Y4vEV
Pramendra Gupta
4
Terima kasih @JapanPro, tetapi saya tidak pernah benar-benar mengalami masalah mengatur batas waktu. Posting ini adalah tentang apa perbedaannya dan mana yang harus digunakan.
Damovisa

Jawaban:

670

Mereka pada dasarnya mencoba melakukan hal yang sama, tetapi setIntervalpendekatan akan lebih akurat daripada setTimeoutpendekatan, karena setTimeoutmenunggu 1000 ms, menjalankan fungsi dan kemudian menetapkan batas waktu lain. Jadi periode menunggu sebenarnya sedikit lebih dari 1000 ms (atau lebih banyak jika fungsi Anda membutuhkan waktu lama untuk dieksekusi).

Meskipun orang mungkin berpikir bahwa setIntervalakan menjalankan tepat setiap 1000 ms, penting untuk dicatat itusetInterval juga akan menunda, karena JavaScript bukan bahasa multi-utas, yang berarti bahwa - jika ada bagian lain dari skrip yang berjalan - interval akan memiliki untuk menunggu sampai selesai.

Dalam Fiddle ini , Anda dapat dengan jelas melihat bahwa batas waktu akan jatuh di belakang, sementara interval hampir sepanjang waktu di hampir 1 panggilan / detik (yang sedang dilakukan skrip). Jika Anda mengubah variabel kecepatan di atas menjadi sesuatu yang kecil seperti 20 (artinya akan mencoba berjalan 50 kali per detik), intervalnya tidak akan pernah mencapai rata-rata 50 iterasi per detik.

Penundaan hampir selalu dapat diabaikan, tetapi jika Anda memprogram sesuatu yang sangat tepat, Anda harus menggunakan pengatur waktu yang dapat menyesuaikan sendiri (yang pada dasarnya adalah pengatur waktu berbasis waktu yang secara konstan menyesuaikan diri untuk penundaan yang dibuatnya)

David Snabel-Caunt
sumber
4
Andy punya saran serupa. Secara hipotesis, apakah ini berarti bahwa jika metode ini membutuhkan lebih dari 1000 ms untuk dijalankan, Anda dapat menjalankan lebih dari satu secara bersamaan?
Damovisa
14
Secara teori, ya. Dalam praktiknya, tidak karena Javascript tidak mendukung multithreading. Jika kode Anda membutuhkan waktu lebih dari 1000 ms, ini akan membekukan browser.
Kamiel Wanrooij
61
Secara teknis, kode tidak akan mengeksekusi tepat setiap 1000 ms, karena tergantung pada resolusi timer dan apakah kode lain sudah dieksekusi. Maksud Anda masih berdiri sekalipun.
Matthew Crumley
10
setInterval berbeda dalam dua cara, 1. setInterval tidak rekursif dan setInterval pertama kali akan memanggil fungsi Anda setelah waktu yang ditentukan sementara setTimeout pertama kali dipanggil tanpa penundaan dan setelah itu akan memanggil lagi setelah waktu yang ditentukan. Setelah eksekusi pertama mereka bekerja hampir sama.
Hafiz
5
Perbedaannya adalah setTimeout tidak terulang. Ini memungkinkan Anda untuk menjalankan skrip setelah waktu yang ditentukan, tetapi hanya sekali. SetInterval di sisi lain akan mengulangi skrip itu, sampai dihentikan dengan clearTimeout ().
Leander
648

Apakah ada perbedaan?

Iya. Timeout mengeksekusi sejumlah waktu tertentu setelah setTimeout () dipanggil; Interval mengeksekusi sejumlah waktu tertentu setelah interval sebelumnya dipecat.

Anda akan melihat perbedaannya jika fungsi doStuff () Anda membutuhkan waktu untuk dijalankan. Misalnya, jika kami mewakili panggilan ke setTimeout / setInterval with ., penembakan timeout / interval dengan *dan eksekusi kode JavaScript dengan [-----], garis waktu terlihat seperti:

Timeout:

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

Interval:

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

Komplikasi berikutnya adalah jika interval menyala sementara JavaScript sudah sibuk melakukan sesuatu (seperti menangani interval sebelumnya). Dalam hal ini, interval diingat, dan terjadi segera setelah penangan sebelumnya selesai dan mengembalikan kontrol ke browser. Jadi misalnya untuk proses doStuff () yang terkadang pendek ([-]) dan kadang-kadang panjang ([-----]):

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

• merepresentasikan interval firing yang tidak bisa langsung mengeksekusi kodenya, dan malah ditunda.

Jadi interval mencoba untuk 'mengejar ketinggalan' untuk kembali sesuai jadwal. Tapi, mereka tidak mengantri satu di atas satu sama lain: hanya akan ada satu eksekusi tertunda per interval. (Jika mereka semua antri, browser akan dibiarkan dengan daftar eksekusi yang terus berkembang!)

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

x mewakili penembakan interval yang tidak bisa mengeksekusi atau dibuat tertunda, jadi malah dibuang.

Jika fungsi doStuff () Anda biasanya membutuhkan waktu lebih lama untuk dieksekusi daripada interval yang ditetapkan untuk itu, browser akan memakan 100% CPU yang mencoba untuk melayaninya, dan mungkin menjadi kurang responsif.

Yang mana yang Anda gunakan dan mengapa?

Chained-Timeout memberikan slot waktu luang yang dijamin ke browser; Interval mencoba memastikan fungsi yang dijalankannya dijalankan sedekat mungkin dengan waktu yang dijadwalkan, dengan mengorbankan ketersediaan browser UI.

Saya akan mempertimbangkan interval untuk animasi satu kali. Saya ingin menjadi semulus mungkin, sementara waktu yang dirantai lebih sopan untuk animasi yang sedang berlangsung yang akan berlangsung sepanjang waktu saat halaman dimuat. Untuk penggunaan yang kurang menuntut (seperti updater sepele menembak setiap 30 detik atau sesuatu), Anda dapat menggunakan keduanya dengan aman.

Dalam hal kompatibilitas browser, setTimeout mendahului setInterval, tetapi semua browser yang Anda temui hari ini mendukung keduanya. Penyerang terakhir selama bertahun-tahun adalah IE Mobile di WinMo <6.5, tetapi mudah-mudahan itu juga sekarang di belakang kita.

bobince
sumber
Tetapi apakah alasan pilihan antara Interval dan Timeout tetap benar bahkan pada platform non-browser, seperti misalnya WebOS atau JIL?
Vid L
2
Cara yang baik untuk melakukan timeout dirantai pada fungsi anonim: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10)
Justin Meyer
1
Dalam hal kompatibilitas browser, meskipun semua browser menyediakan kedua metode, kinerjanya berbeda.
unigg
"Tetapi kemungkinan itu tidak mendukung hal lain yang Anda gunakan" begitu sangat benar
Dasar
1
mesin drum oleh proyek chromium menggunakan setTimeout ("schedule ()", 0); Jadi browser tidak akan memiliki tumpukan yang tidak perlu ketika itu adalah tab latar belakang untuk chrome atau kekurangan sumber daya.
Elliot Yap
91

setInterval ()

setInterval()adalah metode eksekusi kode berbasis interval waktu yang memiliki kemampuan asli untuk berulang kali menjalankan skrip yang ditentukan ketika interval tercapai. Seharusnya tidak disarangkan ke fungsi callback oleh penulis skrip untuk membuatnya loop, karena loop secara default . Itu akan terus menembak pada interval kecuali jika Anda memanggil clearInterval().

Jika Anda ingin mengulang kode untuk animasi atau centang jam, kemudian gunakan setInterval().

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

setTimeout ()

setTimeout()adalah metode eksekusi kode berbasis waktu yang akan mengeksekusi skrip hanya satu kali ketika interval tercapai. Itu tidak akan diulang lagi kecuali Anda mengarahkannya ke loop script dengan bersarang setTimeout()objek di dalam fungsi yang dipanggil untuk dijalankan. Jika diarahkan untuk loop, itu akan terus menembak pada interval kecuali Anda menelepon clearTimeout().

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

Jika Anda ingin sesuatu terjadi satu kali setelah jangka waktu tertentu, maka gunakan setTimeout(). Itu karena hanya dijalankan satu kali ketika interval yang ditentukan tercapai.

Haris
sumber
6
Penjelasan yang bagus tetapi perhatikan bahwa OP memahami perbedaan dasar dalam contoh yang diberikan OP. Secara khusus, perhatikan bahwa dalam contoh OP setTimeout(), setTimeout()disebut secara rekursif , sedangkan setInterval()tidak.
DavidRR
44

SetInterval memudahkan untuk membatalkan eksekusi kode Anda di masa mendatang. Jika Anda menggunakan setTimeout, Anda harus melacak id timer jika Anda ingin membatalkannya nanti.

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

myTimeoutFunction();

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

melawan

function myTimeoutFunction()
{
    doStuff();
}

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

// later on...
clearInterval(timerId);
Kamiel Wanrooij
sumber
35
Saya tidak melihat bagaimana Anda tidak melacak id timer dalam hal setInterval. Itu baru saja dikeluarkan dari fungsinya.
Kekoa
1
Pilihan lain dengan setTimeoutdaripada menyimpan id menambahkan ifpernyataan untuk hanya mengatur batas waktu berikutnya ketika beberapa kondisi benar.
nnnnnn
7
Kekoa, poin bagus. Tetapi Anda harus menyimpan id interval hanya sekali. Id batas waktu mungkin berubah dengan setiap doa, jadi Anda harus melacak perubahan ini. Kode yang ingin menghapus batas waktu harus memiliki akses ke nilai variabel saat ini. Selain itu tidak mungkin untuk menghapus batas waktu saat berjalan doStuffkarena id tidak valid. Namun, itu tidak benar-benar perlu untuk menyimpan id batas waktu. Sebaliknya, Anda bisa berhenti menelepon setTimeout.
Robert
4
Dalam pengalaman saya, sebagian besar waktu yang Anda inginkan dapat dibatalkan bahkan saat menggunakan setTimeout. 99% dari waktu yang ingin Anda batalkan sebelumnya doa berikutnya terjadi, bukan setelah yang berikutnya selesai.
Kamiel Wanrooij
23

Saya menemukan setTimeoutmetode ini lebih mudah digunakan jika Anda ingin membatalkan batas waktu:

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

myTimeoutFunction();

Juga, jika ada sesuatu yang salah dalam fungsi itu hanya akan berhenti mengulangi pada kesalahan pertama kali, alih-alih mengulangi kesalahan setiap detik.

Guffa
sumber
20

Perbedaannya adalah dalam tujuan mereka.

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

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

Sesederhana itu

Rincian lebih lanjut di sini http://javascript.info/tutorial/settimeout-setinterval

kmario23
sumber
7
Penjelasan singkat yang bagus tetapi perhatikan bahwa OP memahami perbedaan mendasar dalam contoh-contoh yang diberikan OP. Secara khusus, perhatikan bahwa dalam contoh OP setTimeout(), setTimeout()disebut secara rekursif , sedangkan setInterval()tidak.
DavidRR
14

Ketika Anda menjalankan beberapa fungsi di dalam setInterval, yang berfungsi lebih banyak daripada waktu habis-> browser akan macet.

- Misalnya, doStuff () membutuhkan 1500 detik. untuk dieksekusi dan Anda lakukan: setInterval (doStuff, 1000);
1) Browser menjalankan doStuff () yang membutuhkan waktu 1,5 detik. Akan dieksekusi;
2) Setelah ~ 1 detik ia mencoba menjalankan doStuff () lagi. Tapi doStuff sebelumnya () masih dijalankan -> jadi browser menambahkan run ini ke antrian (untuk dijalankan setelah yang pertama dilakukan).
3,4, ..) Penambahan yang sama ke antrian eksekusi untuk iterasi berikutnya, tetapi doStuff () dari sebelumnya masih dalam proses ...
Akibatnya, browser macet.

Untuk mencegah perilaku ini, cara terbaik adalah menjalankan setTimeout di dalam setTimeout untuk meniru setInterval .
Untuk memperbaiki batas waktu antara panggilan setTimeout, Anda dapat menggunakan alternatif koreksi sendiri untuk teknik setInterval JavaScript .

Serg Hospodarets
sumber
1
Saya tidak tahu mengapa tidak ada yang menemukan nilai dalam jawaban ini!
Randika Vishman
9

Saya menggunakan setTimeout.

Rupanya bedanya setTimeout memanggil metode sekali, setInterval memanggilnya berulang kali.

Berikut adalah artikel bagus yang menjelaskan perbedaannya: Tutorial: Pengatur waktu JavaScript dengan setTimeout dan setInterval

Bravax
sumber
2
Yap, aku perbedaan itu, tetapi dua potong kode saya berikan maka harus melakukan hal yang sama ...
Damovisa
Ummm ya ... saya akan berpikir ... tetapi menurut dcaunt dan jumlah suaranya tidak cukup apa yang terjadi.
Bravax
9

Kode Anda akan memiliki inteval eksekusi yang berbeda, dan dalam beberapa proyek, seperti game online, itu tidak dapat diterima. Pertama, apa yang harus Anda lakukan, untuk membuat kode Anda bekerja dengan inteval yang sama, Anda harus mengubah "myTimeoutFunction" menjadi ini:

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

Setelah perubahan ini, itu akan sama dengan

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

Tetapi, Anda masih akan memiliki hasil yang tidak stabil, karena JS adalah single-threaded. Untuk saat ini, jika utas JS akan sibuk dengan sesuatu, itu tidak akan dapat menjalankan fungsi panggilan balik Anda, dan eksekusi akan ditunda selama 2-3 msec. Apakah Anda memiliki 60 eksekusi per detik, dan setiap kali Anda memiliki penundaan acak 1-3 detik, itu sama sekali tidak dapat diterima (setelah satu menit akan ada sekitar 7200 msec penundaan), dan saya dapat saran untuk menggunakan sesuatu seperti ini:

    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();

Kode ini akan menjamin periode eksekusi yang stabil. Bahkan utas akan sibuk, dan kode Anda akan dieksekusi setelah 1005 mseconds, lain kali akan ada waktu habis untuk 995 msec, dan hasilnya akan stabil.

menurun
sumber
7

Saya sudah membuat tes sederhana setInterval(func, milisec) , karena saya ingin tahu apa yang terjadi ketika konsumsi waktu fungsi lebih besar daripada durasi interval.

setIntervalumumnya akan menjadwalkan iterasi berikutnya tepat setelah dimulainya iterasi sebelumnya, kecuali fungsi masih berlangsung . Jika demikian, setIntervalakan menunggu, hingga fungsi berakhir. Segera setelah itu terjadi, fungsi segera dipecat lagi - tidak ada menunggu untuk iterasi berikutnya sesuai jadwal (karena akan berada dalam kondisi tanpa waktu melebihi fungsi). Juga tidak ada situasi dengan iterasi paralel yang berjalan.

Saya sudah menguji ini di Chrome v23. Saya harap ini adalah implementasi deterministik di semua browser modern.

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

Output konsol:

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

The waitFungsi ini hanya memblokir pembantu benang - sinkron panggilan ajax yang mengambil persis 2500 milidetik pengolahan di sisi server:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
jwaliszko
sumber
1
"tidak ada situasi dengan iterasi paralel yang berjalan" - ya, ini seharusnya tidak mungkin. JavaScript sisi klien memiliki model eksekusi berulir tunggal sehingga tidak ada (pengendali acara, dll.) Yang pernah terjadi pada saat yang sama. Itulah sebabnya tidak ada yang terjadi (dan browser tidak responsif) selama panggilan ajax sinkron.
MrWhite
Apakah browser responsif dalam beberapa ms antara "interval"? Apakah acara lain akan menyala jika sedang menunggu? (Terima kasih atas tes dengan +1)
MrWhite
1
Menurut MDN, itu dianggap " penggunaan berbahaya " jika fungsi bisa mengeksekusi lebih lama dari interval waktu. setTimoutPanggilan rekursif lebih disukai.
MrWhite
6

Untuk melihatnya sedikit berbeda: setInterval memastikan bahwa kode dijalankan pada setiap interval yang diberikan (yaitu 1000 ms, atau berapa banyak yang Anda tentukan) sementara setTimeout menetapkan waktu yang 'ditunggu hingga' ia menjalankan kode. Dan karena dibutuhkan milidetik tambahan untuk menjalankan kode, ia menambahkan hingga 1000 ms dan karenanya, setTimeout berjalan lagi pada waktu yang tidak tepat (lebih dari 1000 ms).

Misalnya, penghitung waktu / hitung mundur tidak dilakukan dengan setTimeout, ini dilakukan dengan setInterval, untuk memastikan itu tidak menunda dan kode berjalan pada interval yang diberikan dengan tepat.

CatalinBerta
sumber
5

Baik setInterval dan setTimeout mengembalikan id timer yang dapat Anda gunakan untuk membatalkan eksekusi, yaitu, sebelum timeout dipicu. Untuk membatalkan Anda memanggil clearInterval atau clearTimeout seperti ini:

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

Juga, batas waktu secara otomatis dibatalkan ketika Anda meninggalkan halaman atau menutup jendela browser.

Helgi
sumber
4

Anda dapat memvalidasi jawaban bobince sendiri ketika Anda menjalankan javascript berikut atau periksa JSFiddle ini

<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);
});
Gudradain
sumber
3

Yah, setTimeout lebih baik dalam satu situasi, seperti yang baru saja saya pelajari. Saya selalu menggunakan setInterval, yang tersisa untuk dijalankan di latar belakang selama lebih dari setengah jam. Ketika saya beralih kembali ke tab itu, tayangan slide (di mana kode digunakan) berubah sangat cepat, bukannya setiap 5 detik yang seharusnya. Sebenarnya hal itu terjadi lagi ketika saya mengujinya lebih lanjut dan apakah itu kesalahan browser atau tidak tidak penting, karena dengan setTimeout situasi itu sama sekali tidak mungkin.

Nino
sumber
Kedengarannya seolah-olah Anda memanggil setInterval di dalam fungsi yang Anda panggil. Begitulah cara Anda mengulang dengan setTimeout, tetapi dengan setInterval Anda sebenarnya membuat loop yang sama sekali baru setiap kali dipanggil.
Stephen R
2

Perbedaannya jelas di konsol:

masukkan deskripsi gambar di sini

testCoder
sumber
2

Hanya menambahkan apa yang telah dikatakan tetapi versi kode setTimeout juga akan mencapai Maximum call stack sizeyang akan menghentikannya dari berfungsi. Karena tidak ada kasing dasar untuk menghentikan fungsi rekursif sehingga Anda tidak bisa menjalankannya selamanya.

Maaz
sumber
Saya pikir ini tidak benar. Lihat di sini stackoverflow.com/questions/8058612/…
Kevin Wheeler
-1

Perbedaan paling umum antara dan setInterval (ekspresi, durasi) adalah itu

setTimeout () hanya akan menjalankan ekspresi SEKALI dan setelah durasi yang ditentukan.

Namun,

setInterval () akan menjalankan ekspresi dalam INFINITE-LOOP setelah setiap durasi yang ditentukan.

Anshu Aditya
sumber
-5

Saya pikir SetIntervaldan SetTimeoutberbeda. SetIntervalmengeksekusi blok sesuai dengan waktu yang ditetapkan sementara, SetTimeoutmengeksekusi blok kode sekali.

Cobalah serangkaian kode ini setelah hitungan mundur batas waktu detik:

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

lalu coba

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

Anda dapat melihat perbedaannya sendiri.

Ugbana Chukwujindu Kelvin
sumber
Ini tidak menjawab pertanyaan. settimeout () dapat digunakan secara rekursif untuk memberikan hasil yang sama dengan setinterval. Pertanyaannya adalah tentang kinerja kedua opsi ini.
Tomas Gonzalez