Jalankan fungsi setInterval tanpa penundaan pertama kali

341

Itu ada cara untuk mengkonfigurasi setIntervalmetode javascript untuk menjalankan metode segera dan kemudian dijalankan dengan timer

Jorge
sumber
4
Tapi tidak secara asli. Anda dapat mencoba menelepon functionsekali dan kemudian melakukansetInterval()
Mrchief

Jawaban:

519

Ini paling sederhana untuk langsung memanggil fungsi itu sendiri secara langsung:

foo();
setInterval(foo, delay);

Namun ada alasan yang baik untuk dihindari setInterval- khususnya dalam beberapa keadaan, seluruh setIntervalperistiwa dapat tiba setelah satu sama lain tanpa penundaan. Alasan lain adalah bahwa jika Anda ingin menghentikan loop Anda harus secara eksplisit memanggil clearIntervalyang berarti Anda harus mengingat pegangan yang dikembalikan dari setIntervalpanggilan asli .

Jadi metode alternatif adalah foomemicu sendiri untuk panggilan berikutnya menggunakan setTimeoutsebagai gantinya:

function foo() {
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);
}

// start the cycle
foo();

Ini menjamin bahwa setidaknya ada interval di delayantara panggilan. Ini juga membuatnya lebih mudah untuk membatalkan loop jika diperlukan - Anda hanya tidak menelepon setTimeoutketika kondisi terminasi loop Anda tercapai.

Lebih baik lagi, Anda bisa membungkus semuanya dalam ekspresi fungsi yang dipanggil langsung yang menciptakan fungsi, yang kemudian memanggil dirinya lagi seperti di atas, dan secara otomatis memulai loop:

(function foo() {
    ...
    setTimeout(foo, delay);
})();

yang mendefinisikan fungsi dan memulai siklus semuanya sekaligus.

Alnitak
sumber
5
Mengapa kamu lebih suka setTimeout?
Sanghyun Lee
19
@Sangdol karena memastikan bahwa acara pengatur waktu tidak "menumpuk" jika dibiarkan tidak diproses. Dalam beberapa keadaan, seluruh rangkaian setIntervalacara dapat tiba segera setelah satu sama lain tanpa penundaan.
Alnitak
8
Seharusnya ada semacam tes yang tidak membiarkan Anda memposting di tumpukan saat Anda lelah
James
3
Bagaimana saya menghentikan fungsi jika saya menggunakan setTimeoutmetode ini?
Gaurav Bhor
6
@DaveMunger tidak, karena itu tidak benar-benar rekursif - itu hanya "pseudo-rekursif". Panggilan "rekursif" tidak terjadi sampai browser kembali ke loop acara, di mana titik tumpukan panggilan telah benar-benar dibatalkan.
Alnitak
210

Saya tidak yakin apakah saya memahami Anda dengan benar, tetapi Anda dapat dengan mudah melakukan sesuatu seperti ini:

setInterval(function hello() {
  console.log('world');
  return hello;
}(), 5000);

Jelas ada sejumlah cara untuk melakukan ini, tapi itu cara paling ringkas yang bisa saya pikirkan.

chjj
sumber
16
Ini adalah jawaban yang keren karena ini adalah fungsi bernama yang dijalankan segera dan juga mengembalikan dirinya sendiri. Persis apa yang saya cari.
jmort253
41
Jelas solusi yang keren, tetapi kemungkinan akan menyebabkan kebingungan bagi orang yang membaca di masa depan.
Deepak Joy
4
Anda tidak perlu memberinya nama 'halo'. Anda bisa mengembalikan arguments.callee dan memiliki fungsi anonim
JochenJung
10
@JochenJung arguments.calleetidak tersedia dalam mode ketat ES5
Alnitak
3
Ini adalah jenis kode Javascript yang akan membingungkan kebanyakan programmer JS baru yang berasal dari bahasa lain. Tulis banyak hal seperti ini jika perusahaan Anda tidak memiliki banyak personel JS dan Anda menginginkan keamanan pekerjaan.
Ian
13

Saya menemukan pertanyaan ini karena masalah yang sama tetapi tidak ada jawaban yang membantu jika Anda perlu berperilaku persis seperti setInterval()tetapi dengan satu - satunya perbedaan fungsi dipanggil segera di awal.

Ini solusi saya untuk masalah ini:

function setIntervalImmediately(func, interval) {
  func();
  return setInterval(func, interval);
}

Keuntungan dari solusi ini:

  • menggunakan kode yang ada setIntervaldapat dengan mudah diadaptasi oleh substitusi
  • bekerja dalam mode ketat
  • ini bekerja dengan fungsi dan penutup bernama yang sudah ada
  • Anda masih dapat menggunakan nilai kembali dan meneruskannya clearInterval()nanti

Contoh:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
        console.log('hello');
    }, 1000);

// clear interval after 4.5 seconds
setTimeout( _ => {
        clearInterval(myInterval);
    }, 4500);

Untuk menjadi kurang ajar, jika Anda benar-benar perlu menggunakan setIntervalmaka Anda juga bisa mengganti yang asli setInterval. Karenanya, tidak diperlukan perubahan kode saat menambahkan ini sebelum kode yang ada:

var setIntervalOrig = setInterval;

setInterval = function(func, interval) {
    func();
    return setIntervalOrig(func, interval);
}

Namun, semua keuntungan sebagaimana tercantum di atas berlaku di sini, tetapi tidak diperlukan penggantian.

Jens Wirth
sumber
Saya lebih suka solusi ini daripada setTimeoutsolusi karena mengembalikan setIntervalobjek. Untuk menghindari fungsi panggilan yang mungkin kemudian dalam kode dan karena itu tidak terdefinisi pada waktu saat ini, saya bungkus panggilan fungsi pertama dalam setTimeoutfungsi seperti ini: setTimeout(function(){ func();},0);Fungsi pertama kemudian dipanggil setelah siklus pemrosesan saat ini, yang juga segera , tetapi lebih banyak kesalahan terbukti.
pensan
8

Anda bisa membungkus setInterval()fungsi yang menyediakan perilaku itu:

function instantGratification( fn, delay ) {
    fn();
    setInterval( fn, delay );
}

... lalu gunakan seperti ini:

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);
pengguna113716
sumber
5
Saya pikir Anda harus mengembalikan apa yang setInterval kembali. Ini karena jika tidak, Anda tidak dapat menggunakan clearInterval.
Henrik R
5

Ini adalah pembungkus untuk cantik-cantik jika Anda membutuhkannya:

(function() {
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) {
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    };
})();

Setel argumen ketiga setInterval ke true dan itu akan berjalan untuk pertama kalinya segera setelah memanggil setInterval:

setInterval(function() { console.log("hello world"); }, 5000, true);

Atau hilangkan argumen ketiga dan itu akan mempertahankan perilaku aslinya:

setInterval(function() { console.log("hello world"); }, 5000);

Beberapa browser mendukung argumen tambahan untuk setInterval yang tidak diperhitungkan oleh wrapper ini; Saya pikir ini jarang digunakan, tetapi ingatlah itu jika Anda memang membutuhkannya.

Mahn
sumber
9
Mengesampingkan fungsi peramban asli sangat buruk karena dapat merusak kode lain yang ada saat spesifikasi berubah. Faktanya, setInterval saat ini memiliki lebih banyak parameter: developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…
Áxel Costas Pena
2

Untuk seseorang perlu membawa bagian luar thisseolah-olah itu adalah fungsi panah.

(function f() {
    this.emit("...");
    setTimeout(f.bind(this), 1000);
}).bind(this)();

Jika sampah yang dihasilkan di atas mengganggu Anda, Anda dapat melakukan penutupan.

(that => {
    (function f() {
        that.emit("...");
        setTimeout(f, 1000);
    })();
})(this);

Atau mungkin mempertimbangkan menggunakan yang @autobinddekorator tergantung pada kode Anda.

Константин Ван
sumber
1

Saya akan menyarankan memanggil fungsi dalam urutan berikut

var _timer = setInterval(foo, delay, params);
foo(params)

Anda juga dapat meneruskannya _timerke foo, jika Anda ingin clearInterval(_timer)pada kondisi tertentu

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);
Jayant Varshney
sumber
Bisakah Anda menjelaskan ini secara lebih mendalam?
Polyducks
Anda mengatur timer dari panggilan kedua, untuk pertama kalinya Anda hanya memanggil fn secara langsung.
Jayant Varshney
1

Ini adalah versi sederhana untuk pemula tanpa semua masalah. Itu hanya menyatakan fungsi, memanggilnya, lalu memulai interval. Itu dia.

//Declare your function here
function My_Function(){
  console.log("foo");
}    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );

Polyducks
sumber
1
Itulah yang dilakukan jawaban yang diterima di beberapa baris pertama. Bagaimana jawaban ini menambahkan sesuatu yang baru?
Dan Dascalescu
Jawaban yang diterima melanjutkan dengan mengatakan tidak melakukan ini. Respons saya terhadap jawaban yang diterima menjelaskan mengapa itu masih merupakan metode yang valid. OP secara khusus meminta untuk memanggil fungsi setInterval pada panggilan pertamanya tetapi jawaban yang diterima mengalihkan untuk berbicara tentang manfaat setTimeout.
Polyducks
0

Untuk mengatasi masalah ini, saya menjalankan fungsi ini pertama kali setelah halaman dimuat.

function foo(){ ... }

window.onload = function() {
   foo();
};

window.setInterval(function()
{
    foo(); 
}, 5000);
dario
sumber
0

Ada paket npm yang mudah disebut firstInterval (pengungkapan penuh, ini milik saya).

Banyak contoh di sini tidak termasuk penanganan parameter, dan mengubah perilaku default setIntervaldalam setiap proyek besar adalah kejahatan. Dari dokumen:

Pola ini

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

identik dengan

firstInterval(callback, 1000, p1, p2);

Jika Anda jadul di peramban dan tidak menginginkan ketergantungan, ini adalah cara mudah dan tempel dari kode.

jimm101
sumber
0

// YCombinator
function anonymous(fnc) {
  return function() {
    fnc.apply(fnc, arguments);
    return fnc;
  }
}

// Invoking the first time:
setInterval(anonymous(function() {
  console.log("bar");
})(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() {
  console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
  console.log("baz");
}, 4000);

Ok ini sangat kompleks, jadi, izinkan saya menjelaskannya lebih sederhana:

function hello(status ) {    
  console.log('world', ++status.count);
  
  return status;
}

setInterval(hello, 5 * 1000, hello({ count: 0 }));

NSD
sumber
Ini sangat direkayasa.
Polyducks
0

Anda dapat mengatur waktu tunda awal yang sangat kecil (mis. 100) dan mengaturnya ke waktu tunda yang Anda inginkan dalam fungsi:

var delay = 100;

function foo() {
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);
}

reo_yamanaka
sumber
-2

Ada masalah dengan panggilan asinkron langsung dari fungsi Anda, karena setTimeout / setInterval standar memiliki batas waktu minimal sekitar beberapa milidetik bahkan jika Anda langsung menetapkannya ke 0. Ini disebabkan oleh pekerjaan khusus browser.

Contoh kode dengan penundaan nol NYATA yang berfungsi di Chrome, Safari, Opera

function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}

Anda dapat menemukan informasi lebih lanjut di sini

Dan setelah panggilan manual pertama Anda dapat membuat interval dengan fungsi Anda.

Xe-Xe
sumber
-10

sebenarnya yang tercepat untuk dilakukan

interval = setInterval(myFunction(),45000)

ini akan memanggil fungsi saya, dan kemudian akan melakukannya setiap 45 detik yang berbeda dari melakukan

interval = setInterval(myfunction, 45000)

yang tidak akan menyebutnya, tapi jadwalkan saja

Hertzel Armengol
sumber
Dari mana Anda mendapatkan itu?
Ken Sharp
2
Ini hanya berfungsi jika myFunction()mengembalikan sendiri. Alih-alih memodifikasi setiap fungsi untuk dipanggil oleh setIntervalitu adalah pendekatan yang lebih baik untuk membungkus setIntervalsekali seperti yang diusulkan jawaban lainnya.
Jens Wirth