Mengubah interval SetInterval saat sedang berjalan

161

Saya telah menulis fungsi javascript yang menggunakan setInterval untuk memanipulasi string setiap sepersepuluh detik untuk sejumlah iterasi tertentu.

function timer() {
    var section = document.getElementById('txt').value;
    var len = section.length;
    var rands = new Array();

    for (i=0; i<len; i++) {
        rands.push(Math.floor(Math.random()*len));
    };

    var counter = 0
    var interval = setInterval(function() {
        var letters = section.split('');
        for (j=0; j < len; j++) {
            if (counter < rands[j]) {
                letters[j] = Math.floor(Math.random()*9);
            };
        };
        document.getElementById('txt').value = letters.join('');
        counter++

        if (counter > rands.max()) {
            clearInterval(interval);
        }
    }, 100);
};

Alih-alih menetapkan interval pada angka tertentu, saya ingin memperbaruinya setiap kali berjalan, berdasarkan penghitung. Jadi alih-alih:

var interval = setInterval(function() { ... }, 100);

Itu akan menjadi sesuatu seperti:

var interval = setInterval(function() { ... }, 10*counter);

Sayangnya, itu tidak berhasil. Sepertinya "10 * penghitung" sama dengan 0.

Jadi, bagaimana saya bisa mengatur interval setiap kali fungsi anonim berjalan?

Joe Di Stefano
sumber

Jawaban:

107

Gunakan setTimeout()sebagai gantinya. Callback kemudian akan bertanggung jawab untuk menembakkan timeout berikutnya, pada titik mana Anda dapat meningkatkan atau memanipulasi waktu.

EDIT

Berikut adalah fungsi umum yang dapat Anda gunakan untuk menerapkan batas waktu "perlambatan" untuk panggilan fungsi APAPUN.

function setDeceleratingTimeout(callback, factor, times)
{
    var internalCallback = function(tick, counter) {
        return function() {
            if (--tick >= 0) {
                window.setTimeout(internalCallback, ++counter * factor);
                callback();
            }
        }
    }(times, 0);

    window.setTimeout(internalCallback, factor);
};

// console.log() requires firebug    
setDeceleratingTimeout(function(){ console.log('hi'); }, 10, 10);
setDeceleratingTimeout(function(){ console.log('bye'); }, 100, 10);
Peter Bailey
sumber
1
Dengan panggilan balik, apakah maksud Anda baris terakhir dari panggilan fungsi itu sendiri secara rekursif dengan setTimeout (..., newInterval)?
Marc
1
Saya menganggap itu yang dia maksud. Saya baru saja mencobanya dan sepertinya berhasil. Terima kasih kawan!
Joe Di Stefano
2
hanya memberi 9 hai :) --tmungkin seharusnya t-- jsfiddle.net/albertjan/by5fd
albertjan
1
Melakukan ini secara rekursif, tidakkah Anda berisiko mengambil tumpukan stack overflow jika timesterlalu besar?
André C. Andersen
4
Menjadi nitpicky di sini, tapi saya harus mengatakan, kode itu cukup sulit dibaca. Jika Anda akan menggunakan kawat gigi lini depan, setidaknya memiliki kesopanan untuk menggunakan indentasi 4-8-ruang atau tidak pernah melampaui 2 indentasi. IMO versi ini jauh lebih mudah dibaca. Juga perhatikan penggantian nama tmenjadi tick, yang merupakan tebakan terbaik saya untuk apa pun "t" yang harus diperjuangkan. tadalah nama variabel yang sangat buruk.
Braden Best
124

Anda dapat menggunakan fungsi anonim:

var counter = 10;
var myFunction = function(){
    clearInterval(interval);
    counter *= 10;
    interval = setInterval(myFunction, counter);
}
var interval = setInterval(myFunction, counter);

UPDATE: Seperti yang disarankan oleh A. Wolff, gunakan setTimeoutuntuk menghindari kebutuhan clearInterval.

var counter = 10;
var myFunction = function() {
    counter *= 10;
    setTimeout(myFunction, counter);
}
setTimeout(myFunction, counter);
nick
sumber
5
Baiklah RozzA, jawaban saya diposting pada 16 Sep '11 dan user28958 pada 22 Agustus '13, jadi saya akan mengambil "perwakilan" terima kasih!
nick
12
Mengapa Anda menggunakan interval, batas waktu yang sederhana akan lebih baik tanpa perlu menghapusnya. misalnya: jsfiddle.net/fgs5nwgn
A. Wolff
4
Saya menempel pada konteks pertanyaan. setTimeout akan bekerja tentu saja
nick
24

Saya suka pertanyaan ini - menginspirasi objek timer kecil dalam diri saya:

window.setVariableInterval = function(callbackFunc, timing) {
  var variableInterval = {
    interval: timing,
    callback: callbackFunc,
    stopped: false,
    runLoop: function() {
      if (variableInterval.stopped) return;
      var result = variableInterval.callback.call(variableInterval);
      if (typeof result == 'number')
      {
        if (result === 0) return;
        variableInterval.interval = result;
      }
      variableInterval.loop();
    },
    stop: function() {
      this.stopped = true;
      window.clearTimeout(this.timeout);
    },
    start: function() {
      this.stopped = false;
      return this.loop();
    },
    loop: function() {
      this.timeout = window.setTimeout(this.runLoop, this.interval);
      return this;
    }
  };

  return variableInterval.start();
};

Contoh penggunaan

var vi = setVariableInterval(function() {
  // this is the variableInterval - so we can change/get the interval here:
  var interval = this.interval;

  // print it for the hell of it
  console.log(interval);

  // we can stop ourselves.
  if (interval>4000) this.stop();

  // we could return a new interval after doing something
  return interval + 100;
}, 100);  

// we can change the interval down here too
setTimeout(function() {
  vi.interval = 3500;
}, 1000);

// or tell it to start back up in a minute
setTimeout(function() {
  vi.interval = 100;
  vi.start();
}, 60000);
gnarf
sumber
4
Terima kasih - arahkan saya ke arah yang benar untuk hal serupa yang sedang saya kerjakan.
Kolonel Sponsz
Sederhana dan efektif. Terima kasih!
Jester
18

Saya memiliki pertanyaan yang sama dengan poster aslinya, apakah ini sebagai solusi. Tidak yakin seberapa efisien ini ....

interval = 5000; // initial condition
var run = setInterval(request , interval); // start setInterval as "run"

    function request() { 

        console.log(interval); // firebug or chrome log
        clearInterval(run); // stop the setInterval()

         // dynamically change the run interval
        if(interval>200 ){
          interval = interval*.8;
        }else{
          interval = interval*1.2;
        }

        run = setInterval(request, interval); // start the setInterval()

    }
pengguna28958
sumber
saya suka jawaban ini lebih baik karena sebenarnya menjawab pertanyaan OP (dan saya). setTimeout dapat ditunda (oleh penggunaan CPU 100%, skrip lain, dll) di mana setInterval TIDAK terpengaruh oleh penundaan itu - membuatnya jauh lebih unggul untuk hal
RozzA
8
Saya 99% yakin bahwa klaim Anda tentang setInterval@RozzA salah - Ini masih mengalami keterlambatan yang sama dengan JavaScript lainnya, dan hampir setiap browser juga mengatur setInterval ke 4ms. Apakah Anda memiliki tautan ke pos tentang ini atau sesuatu?
gnarf
9

Ini adalah cara saya melakukan ini, saya menggunakan setTimeout:

var timer = {
    running: false,
    iv: 5000,
    timeout: false,
    cb : function(){},
    start : function(cb,iv){
        var elm = this;
        clearInterval(this.timeout);
        this.running = true;
        if(cb) this.cb = cb;
        if(iv) this.iv = iv;
        this.timeout = setTimeout(function(){elm.execute(elm)}, this.iv);
    },
    execute : function(e){
        if(!e.running) return false;
        e.cb();
        e.start();
    },
    stop : function(){
        this.running = false;
    },
    set_interval : function(iv){
        clearInterval(this.timeout);
        this.start(false, iv);
    }
};

Pemakaian:

timer.start(function(){
    console.debug('go');
}, 2000);

timer.set_interval(500);

timer.stop();
Jaapze
sumber
+1, saya memodifikasinya sedikit untuk keperluan saya sehingga saya dapat menggunakan beberapa interval variabel - jsfiddle.net/h70mzvdq
Dallas
Juga memodifikasi set_intervalfungsi untuk TIDAK memulai eksekusi baru kecuali interval baru lebih kecil dari yang lama ..if (iv < this.iv) { clearInterval(this.timeout); this.start(false, iv); } else { this.iv = iv; }
Dallas
9

Cara yang lebih sederhana adalah dengan memiliki ifpernyataan dalam fungsi yang disegarkan dan kontrol untuk mengeksekusi perintah Anda secara berkala. Dalam contoh berikut, saya menjalankan peringatan setiap 2 detik dan interval ( intrv) dapat diubah secara dinamis ...

var i=1;
var intrv=2; // << control this variable

var refreshId = setInterval(function() {
  if(!(i%intrv)) {
    alert('run!');
  }
  i++;
}, 1000);
Kiril Cvetkov
sumber
Ini juga favorit pribadi saya. kecil, sederhana, dapat diperpanjang.
cowok mograbi
Saya ingin solusi dari penghambat waktu yang dapat mengatur ulang laju berdasarkan peristiwa aplikasi; ini bertemu yang perlu sederhana dan sempurna. Terima kasih.
Andrew Brown
Ini keren tetapi juga interval waktu pada saat Anda tidak membutuhkannya ... juga agak tidak terbaca. Untuk alasan ini saya lebih suka setTimeout secara pribadi.
Kokodoko
4

Ini dapat dimulai sesuai keinginan Anda. timeout adalah metode yang saya gunakan untuk tetap di atas jam.

Saya membutuhkan setiap jam untuk memulai blok kode pada jam tersebut. Jadi ini akan dimulai pada startup server dan menjalankan interval setiap jam. Pada dasarnya langkah awal adalah memulai interval dalam menit yang sama. Jadi dalam satu detik dari init, jalankan segera lalu setiap 5 detik.

var interval = 1000;
var timing =function(){
    var timer = setInterval(function(){
        console.log(interval);
        if(interval == 1000){ /*interval you dont want anymore or increment/decrement */
            interval = 3600000; /* Increment you do want for timer */
            clearInterval(timer);
            timing();
        }
    },interval);
}
timing();

Bergantian jika Anda ingin memiliki sesuatu terjadi di awal dan kemudian selamanya pada interval tertentu Anda bisa menyebutnya pada waktu yang sama dengan setInterval. Sebagai contoh:

var this = function(){
 //do
}
setInterval(function(){
  this()
},3600000)
this()

Di sini kita menjalankan ini pertama kali dan kemudian setiap jam.

Dgerena
sumber
3

Jawaban sederhana adalah Anda tidak dapat memperbarui interval waktu yang sudah dibuat . (Hanya ada dua fungsi setInterval/setTimerdan clearInterval/clearTimer, jadi memiliki timerIdAnda hanya dapat menonaktifkannya.) Tetapi Anda dapat membuat beberapa solusi. Lihatlah repo github ini .

vbarbarosh
sumber
2

Saya tidak dapat menyinkronkan dan mengubah kecepatan setIntervals saya juga dan saya akan mengirim pertanyaan. Tapi saya pikir saya sudah menemukan cara. Ini tentu harus ditingkatkan karena saya seorang pemula. Jadi, saya dengan senang hati membaca komentar / komentar Anda tentang ini.

<body onload="foo()">
<div id="count1">0</div>
<div id="count2">2nd counter is stopped</div>
<button onclick="speed0()">pause</button>
<button onclick="speedx(1)">normal speed</button>
<button onclick="speedx(2)">speed x2</button>
<button onclick="speedx(4)">speed x4</button>
<button onclick="startTimer2()">Start second timer</button>
</body>
<script>
var count1 = 0,
    count2 = 0,
    greenlight = new Boolean(0), //blocks 2nd counter
    speed = 1000,   //1second
    countingSpeed;
function foo(){
    countingSpeed = setInterval(function(){
        counter1();
        counter2();
    },speed);
}
function counter1(){
    count1++;
    document.getElementById("count1").innerHTML=count1;
}
function counter2(){
    if (greenlight != false) {
        count2++;
        document.getElementById("count2").innerHTML=count2;
    }
}
function startTimer2(){
    //while the button hasn't been clicked, greenlight boolean is false
    //thus, the 2nd timer is blocked
    greenlight = true;
    counter2();
    //counter2() is greenlighted
}

//these functions modify the speed of the counters
function speed0(){
    clearInterval(countingSpeed);
}
function speedx(a){
    clearInterval(countingSpeed);
    speed=1000/a;
    foo();
}
</script>

Jika Anda ingin counter untuk mulai meningkat setelah halaman dibuka, dimasukkan counter1()dan counter2()di foo()sebelum countingSpeeddisebut. Jika tidak, diperlukan speedmilidetik sebelum eksekusi. EDIT: Jawaban lebih pendek.

BEAGMB
sumber
2
(function variableInterval() {
    //whatever needs to be done
    interval *= 2; //deal with your interval
    setTimeout(variableInterval, interval);
    //whatever needs to be done
})();

tidak bisa lebih pendek

mikakun
sumber
1

Saya seorang pemula dalam javascript, dan tidak menemukan bantuan dalam jawaban sebelumnya (tetapi banyak ide bagus).
Sepotong kode di bawah ini mempercepat (akselerasi> 1) atau melambat (akselerasi <1). Saya harap ini dapat membantu beberapa orang:

function accelerate(yourfunction, timer, refresh, acceleration) {
    var new_timer = timer / acceleration;
    var refresh_init = refresh;//save this user defined value
    if (refresh < new_timer ){//avoid reseting the interval before it has produced anything.
        refresh = new_timer + 1 ;
    };
    var lastInter = setInterval(yourfunction, new_timer);
    console.log("timer:", new_timer);
    function stopLastInter() {
        clearInterval(lastInter);
        accelerate(yourfunction, new_timer, refresh_init, acceleration);
        console.log("refresh:", refresh);
    };
    setTimeout(stopLastInter, refresh);
}

Dengan:

  • timer: nilai awal setInterval dalam ms (meningkat atau menurun)
  • refresh: waktu sebelum nilai baru timerdihitung. Ini adalah langkah panjangnya
  • factor: kesenjangan antara nilai lama dan selanjutnya timer. Ini adalah tinggi langkah
mquantin
sumber
1

Buat fungsi baru:

// set Time interval
$("3000,18000").Multitimeout();

jQuery.fn.extend({
    Multitimeout: function () {
        var res = this.selector.split(",");
        $.each(res, function (index, val) { setTimeout(function () { 
            //...Call function
            temp();
        }, val); });
        return true;
    }
});

function temp()
{
    alert();
}
doshi smit
sumber
1

Berikut ini cara lain untuk membuat timer interval perlambatan / akselerasi. Interval dikalikan dengan faktor hingga total waktu terlampaui.

function setChangingInterval(callback, startInterval, factor, totalTime) {
    let remainingTime = totalTime;
    let interval = startInterval;

    const internalTimer = () => {
        remainingTime -= interval ;
        interval *= factor;
        if (remainingTime >= 0) {
            setTimeout(internalTimer, interval);
            callback();
        }
    };
    internalTimer();
}
jo_va
sumber
0
var counter = 15;
var interval = setTimeout(function(){
    // your interval code here
    window.counter = dynamicValue;
    interval();
}, counter);
Hamidreza
sumber
beri aku kesalahan: Uncaught TypeError: interval is not a functiontapi ini berhasil: jsfiddle.net/fgs5nwgn
Nabi KAZ
0

Terinspirasi oleh panggilan balik internal di atas, saya membuat fungsi untuk memecat panggilan balik dalam sepersekian menit. Jika batas waktu diatur ke interval seperti 6.000, 15.000, 30.000, 60.000 akan terus menyesuaikan interval dalam sinkronisasi ke transisi yang tepat ke menit berikutnya jam sistem Anda.

//Interval timer to trigger on even minute intervals
function setIntervalSynced(callback, intervalMs) {

    //Calculate time to next modulus timer event
    var betterInterval = function () {
        var d = new Date();
        var millis = (d.getMinutes() * 60 + d.getSeconds()) * 1000 + d.getMilliseconds();
        return intervalMs - millis % intervalMs;
    };

    //Internal callback
    var internalCallback = function () {
        return function () {
            setTimeout(internalCallback, betterInterval());
            callback();
        }
    }();

    //Initial call to start internal callback
    setTimeout(internalCallback, betterInterval());
};
flodis
sumber