Thay đổi khoảng thời gian SetInterval khi nó đang chạy


161

Tôi đã viết một hàm javascript sử dụng setInterval để thao tác một chuỗi mỗi phần mười giây cho một số lần lặp nhất định.

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

Thay vì đặt khoảng thời gian ở một số cụ thể, tôi muốn cập nhật nó mỗi khi nó chạy, dựa trên bộ đếm. Vì vậy, thay vì:

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

Nó sẽ giống như:

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

Thật không may, điều đó đã không làm việc. Có vẻ như "bộ đếm 10 *" bằng 0.

Vì vậy, làm thế nào tôi có thể điều chỉnh khoảng thời gian mỗi khi chức năng ẩn danh chạy?

Câu trả lời:


107

Sử dụng setTimeout()thay thế. Cuộc gọi lại sau đó sẽ chịu trách nhiệm bắn thời gian chờ tiếp theo, tại thời điểm đó bạn có thể tăng hoặc thao tác thời gian.

BIÊN TẬP

Đây là một chức năng chung mà bạn có thể sử dụng để áp dụng thời gian chờ "giảm tốc" cho bất kỳ cuộc gọi chức năng nào.

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

1
Bằng cách gọi lại, bạn có nghĩa là dòng cuối cùng của hàm gọi chính nó một cách đệ quy với setTimeout (..., newInterval)?
Marc

1
Tôi cho rằng đó là những gì anh ấy có nghĩa. Tôi chỉ thử điều đó và nó dường như đang hoạt động. Cảm ơn các bạn!
Joe Di Stefano

2
chỉ cung cấp cho 9 hi :) --tcó lẽ nên là t-- jsfiddle.net/albertjan/by5fd
albertjan

1
Làm điều này một cách đệ quy không bạn có nguy cơ bị lỗi tràn ngăn xếp nếu timesquá lớn không?
André C. Andersen

4
Trở nên khó chịu ở đây, nhưng tôi phải nói rằng, mã đó khá khó đọc. Nếu bạn sẽ sử dụng niềng răng tiếp theo, ít nhất phải có khả năng sử dụng thụt 4-8 không gian hoặc không bao giờ vượt quá 2 lần thụt. IMO phiên bản này dễ đọc hơn nhiều. Ngoài ra, hãy lưu ý đến việc đổi tên tthành tick, đó là dự đoán tốt nhất của tôi về bất kỳ "t" nào được cho là phù hợp. tlà một tên biến khá xấu.
Braden hay nhất

124

Bạn có thể sử dụng một chức năng ẩn danh:

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

CẬP NHẬT: Theo đề xuất của A. Wolff, sử dụng setTimeoutđể tránh sự cần thiết clearInterval.

var counter = 10;
var myFunction = function() {
    counter *= 10;
    setTimeout(myFunction, counter);
}
setTimeout(myFunction, counter);

5
Vâng RozzA, câu trả lời của tôi đã được đăng vào ngày 16 tháng 9 năm11 và người dùng28958 vào ngày 22 tháng 8 năm 13, vì vậy tôi sẽ cảm ơn "đại diện"!
nick

12
Tại sao bạn sử dụng một khoảng thời gian, một thời gian chờ đơn giản sẽ tốt hơn mà không cần phải xóa nó. ví dụ: jsfiddle.net/fss5nwgn
A. Wolff

4
Tôi đã bám vào bối cảnh của câu hỏi. setTimeout sẽ hoạt động tất nhiên
nick

24

Tôi thích câu hỏi này - lấy cảm hứng từ một đối tượng hẹn giờ nhỏ trong tôi:

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

Ví dụ sử dụng

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

4
Cảm ơn - đặt tôi đi đúng hướng cho một cái gì đó tương tự tôi đang làm việc.
Đại tá Sponsz

Đơn giản và hiệu quả. Cảm ơn!
Jester

18

Tôi đã có câu hỏi tương tự như poster ban đầu, đã làm điều này như một giải pháp. Không chắc cách này hiệu quả ....

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

    }

Tôi thích câu trả lời này tốt hơn vì nó thực sự trả lời câu hỏi của OP (và của tôi). setTimeout có thể bị trì hoãn (bằng cách sử dụng 100% cpu, các tập lệnh khác, v.v.) khi mà setInterval KHÔNG bị ảnh hưởng bởi các độ trễ đó - làm cho nó vượt trội hơn nhiều so với nội dung 'thời gian thực'
RozzA

8
Tôi chắc chắn 99% rằng khiếu nại của bạn setIntervallà sai @RozzA - Nó vẫn chịu sự chậm trễ giống như bất kỳ JavaScript nào khác và hầu như mọi trình duyệt cũng kẹp setInterval thành 4ms. Bạn có một liên kết đến một bài viết về điều này hoặc một cái gì đó?
gnarf

9

Đây là cách của tôi để làm điều này, tôi sử dụng 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);
    }
};

Sử dụng:

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

timer.set_interval(500);

timer.stop();

+1, tôi đã sửa đổi nó một chút cho mục đích của mình để tôi có thể sử dụng nhiều khoảng biến - jsfiddle.net/h70mzvdq
Dallas

Đồng thời sửa đổi set_intervalchức năng để KHÔNG khởi động một thực thi mới trừ khi khoảng thời gian mới nhỏ hơn khoảng thời gian cũ ..if (iv < this.iv) { clearInterval(this.timeout); this.start(false, iv); } else { this.iv = iv; }
Dallas

9

Một cách đơn giản hơn nhiều sẽ là có một ifcâu lệnh trong hàm được làm mới và điều khiển để thực thi lệnh của bạn theo các khoảng thời gian thông thường. Trong ví dụ sau, tôi chạy cảnh báo cứ sau 2 giây và khoảng thời gian ( intrv) có thể được thay đổi linh hoạt ...

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

var refreshId = setInterval(function() {
  if(!(i%intrv)) {
    alert('run!');
  }
  i++;
}, 1000);

Đây là sở thích cá nhân của tôi quá. nhỏ, đơn giản, mở rộng.
anh chàng mograbi

Tôi muốn một giải pháp về bộ đếm thời gian giảm tốc có thể thiết lập lại tốc độ của nó dựa trên các sự kiện ứng dụng; điều này đáp ứng nhu cầu đơn giản và hoàn hảo. Cảm ơn bạn.
Andrew Brown

Thật tuyệt nhưng nó cũng kích hoạt những khoảng thời gian mà bạn không cần nó ... cũng hơi khó đọc. Vì những lý do này, tôi thích setTimeout cá nhân hơn.
Kokodoko

4

Điều này có thể được bắt đầu theo cách bạn muốn. thời gian chờ là phương pháp tôi đã sử dụng để giữ nó trên đầu giờ.

Tôi có nhu cầu mỗi giờ để bắt đầu một khối mã vào giờ. Vì vậy, điều này sẽ bắt đầu khi máy chủ khởi động và chạy khoảng thời gian hàng giờ. Về cơ bản việc chạy ban đầu là bắt đầu khoảng thời gian trong cùng một phút. Vì vậy, trong một giây từ init, hãy chạy ngay sau đó cứ sau 5 giây.

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

Thay phiên nếu bạn muốn có một cái gì đó xảy ra khi bắt đầu và sau đó mãi mãi ở một khoảng thời gian cụ thể, bạn có thể gọi nó cùng lúc với setInterval. Ví dụ:

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

Ở đây chúng tôi có điều này chạy lần đầu tiên và sau đó mỗi giờ.


3

Câu trả lời đơn giản là bạn không thể cập nhật một khoảng thời gian đã được tạo . (Chỉ có hai chức năng setInterval/setTimerclearInterval/clearTimervì vậy, có một chức năng timerIdbạn chỉ có thể tắt nó.) Nhưng bạn có thể thực hiện một số cách giải quyết. Hãy nhìn vào repo github này .


2

Tôi không thể đồng bộ hóa và thay đổi tốc độ thiết lập của mình và tôi cũng sắp đăng một câu hỏi. Nhưng tôi nghĩ rằng tôi đã tìm thấy một cách. Nó chắc chắn nên được cải thiện bởi vì tôi là người mới bắt đầu. Vì vậy, tôi rất vui khi đọc những bình luận / nhận xét của bạn về điều này.

<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>

Nếu bạn muốn các bộ đếm bắt đầu tăng sau khi trang được tải, hãy đặt counter1()counter2()vào foo()trước countingSpeedđược gọi. Nếu không, phải mất một speedphần nghìn giây trước khi thực hiện. EDIT: Câu trả lời ngắn hơn.


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

không thể rút ngắn


1

Tôi là người mới bắt đầu sử dụng javascript và không tìm thấy bất kỳ trợ giúp nào trong các câu trả lời trước đó (nhưng nhiều ý tưởng hay).
Đoạn mã dưới đây tăng tốc (tăng tốc> 1) hoặc giảm tốc (tăng tốc <1). Tôi hy vọng nó có thể giúp một số người:

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

Với :

  • timer: giá trị ban đầu setInterval tính bằng ms (tăng hoặc giảm)
  • refresh: thời gian trước khi giá trị mới timerđược tính. Đây là bước dài
  • factor: khoảng cách giữa timergiá trị cũ và giá trị tiếp theo . Đây là chiều cao bước

1

Tạo chức năng mới:

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

1

Đây là một cách khác để tạo một bộ đếm thời gian giảm tốc / tăng tốc. Khoảng thời gian được nhân với một yếu tố cho đến khi tổng thời gian bị vượt quá.

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

0
var counter = 15;
var interval = setTimeout(function(){
    // your interval code here
    window.counter = dynamicValue;
    interval();
}, counter);

cho tôi lỗi: Uncaught TypeError: interval is not a functionnhưng điều này đã làm việc: jsfiddle.net/fgs5nwgn
Nabi KAZ

0

Lấy cảm hứng từ cuộc gọi lại nội bộ ở trên, tôi đã thực hiện một chức năng để thực hiện một cuộc gọi lại với phân số phút. Nếu thời gian chờ được đặt thành các khoảng như 6 000, 15 000, 30 000, 60 000, nó sẽ liên tục điều chỉnh các khoảng thời gian đồng bộ hóa để chuyển chính xác sang phút tiếp theo của đồng hồ hệ thống của bạn.

//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());
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.