2013-12-08 58 views
3

比方說,我有一個功能log()Javascript時間:我如何每5,7和8秒執行一次函數?

var log = function(i) { 
    console.log('Executing at time: ' + i); 
} 

而且我想在某個區間執行log(),每x,y和z秒?

讓我們隨意設置X,Y和Z 5,7,和8

var x = 5; 
var y = 7; 
var z = 8; 

而且每x,y和z秒我想打電話給log()

// Every 5 seconds: 
log(x); 
// Every 7 seconds: 
log(y); 
// Every 8 seconds: 
log(z); 

我可以嘗試使用三個setTimeout()來單獨運行這些功能。但是等一下,javascript是不是異步的,所以執行一個setTimeout()會阻止另外兩個執行......嗯......

我可以計算出在時間上的差異,這樣就造成了第一個延遲setTimeout()不會打破第二和第三的時間:

// x is at 5 seconds, run 5000 milliseconds after the start 
setTimeout(function() { log(x); }, 5000); 
// y is at 7 seconds after start, or 2000 milliseconds after x is done 
setTimeout(function() { log(y); }, 2000); 
// z is at 7 seconds after start, or 1000 milliseconds after y is done 
setTimeout(function() { log(z); }, 1000); 

但時間絕不會完全正確的,因爲我log()函數的執行將至少需要的少量時間。此外,當我嘗試在其中添加更多log()命令時,或者當我嘗試以設定的時間間隔重複整個過程時,這會變得雜亂無章。

我可以用一個環路,算上秒,和在x,y和ZTH第二,執行我的命令:

var i = 0; 
while(i<10) { 
    // wait 1 second (pointless function, don't know a better way to wait a second) 
    setTimeout(function() { console.log(' ... '); }, 1000); 
    i++; 

    // execute x, y, or z depending on what time it is 
    switch(i) { 
     case 4: 
      log(x); 
     case 6: 
      log(y); 
     case 7: 
      log(z); 
    } 
} 

但「計數」,這種方法,其中,我執行無用命令使用setTimeout(),真的讓我感到低效。

有沒有更好的方法來測量JavaScript中的時間,並在將來的某個時間執行一個函數?對我而言,關鍵在於它不僅僅是「每5秒運行一次log()」,因爲我明白這一點。它「在時間x,y和z上運行log()」令我困惑。

+0

爲什麼不只是'setInterval(func1,5000); setInterval(func2,7000); setInterval(func3,8000);'? –

+0

有沒有辦法讓時間完全與JS完美。 'setInterval'和'setTimeout'只能保證*在間隔過去之後*嘗試*運行函數*。他們不強制*確切*間隔已經過去。 – zzzzBov

+0

既然你關心例程本身引入的時間延遲,也許網絡工作者會在這裏幫忙?也就是說,每5,7和8秒,你就把例行程序傳遞給一個不妨礙執行其他呼叫的工作者。 – Marc

回答

1

您可以使用函數「setInterval」。這裏有一個例子:

var interval1Id = setInterval(function(){ 
    console.log("logging every 5 seconds"); 
},5000); 

var interval2Id = setInterval(function(){ 
    console.log("logging every 7 seconds"); 
},7000); 

var interval3Id = setInterval(function(){ 
    console.log("logging every 8 seconds"); 
},8000); 

變量「intervalXId」保存,以防萬一你要停止任何間隔。

+0

爲什麼OP應該使用'setInterval'呢?請解釋它是如何解決這個問題的。 –

+0

當你使用「setTimeout」時,你推遲了一段代碼的執行,但是當你使用「setInteval」時,你說你想每X次執行一段代碼。 – geonunez

+0

我知道'setInterval'和'setTimeout'之間的區別。我問它如何解決OP的問題。 –

0

簡單的解決方案是設置一個每秒調用一次的定時器功能,並保持經過了多少秒的計數;如果計數是5,7或8的倍數,則定時器函數會調用您要執行的函數。

+0

這就是我在帖子中討論的。這不是沒有效率嗎? 如果我要使用這種方法,是否有一個適當的方法來「計算」時間?和in一樣,除了在setTimeout()中調用一個無用的函數? –

+0

我認爲這種方法很好。你的基本問題是你需要設置一個循環,所以你需要鏈接函數來執行5 7 8秒,並且我假設循環中的8秒重新開始,是的?因此,從每秒運行的函數進行篩選是合理的,或者您可以創建一個執行function1,等待5秒,執行function2,等待2秒,執行function3,等待1秒,執行function1(重複)的鏈。 – jm0

0

您需要設置前一個內部的下一個超時:

// x is at 5 seconds, run 5000 milliseconds after the start 
setTimeout(function() { 
    log(x); 
    setTimeout(function() { 
    log(y); 
    setTimeout(function() { 
     log(z); 
    }, 1000); 
    }, 2000); 

}, 5000); 

這樣,你不安排前面所有的超時,但只有一個的時候,有少的錯誤的保證金(第二超時將第一啓動後即將結束,等等。

編輯 我居然錯過了OP希望這個重複。在這種情況下,你只需要與一個名字的第一個函數表達式而不是一個匿名的,並在最後調用它:

setTimeout(function entry() { 
    log(x); 
    setTimeout(function() { 
    log(y); 
    setTimeout(function() { 
     log(z); 
     setTimeout(entry, 5000); 
    }, 1000); 
    }, 2000); 
}, 5000); 

我的評論是要避免嵌套,所以你可以有一個類似承諾的方法。 請注意,也可以使用jm0這樣的附加功能來做到這一點,但這是對範圍的額外污染,使用函數表達式可以避免這種情況。

+0

是的,這是我一直在得到的。只需要把它放在一個循環中,也許可以概括一下,以便爲你構建函數。否則後面添加的任何功能都需要重新鏈接。最後有人有意義...... – jm0

+0

如果你想同時有一個超時,只有當前一個超時時才計劃。但是,你可以編寫一個實用函數來鏈接它。 – ZER0

+0

是的,你可以。看到我的遞歸函數在下面! teamworKed – jm0

0

嗯天真的解決方案可能是這樣的。不過,如果你只有這三個區間,那麼使用jQuery是一個很好的解決方案,那就是使用deferrds。

function log (val) { 
    console.log(val); 
} 

var intervals = [{interval: 5000, logVal: 'x', logged: false}, 
       {interval: 7000, logVal: 'y', logged: false}, 
       {interval: 8000, logVal: 'z', logged: false}]; 

var startTime; 

function myLog() { 
    var endTime = new Date().getTime(); 
    var diff = endTime - startTime; 

    for (var i = 0; i < (intervals.length - 1); i++) { 
     if (diff >= intervals[i].interval && diff < intervals[i+1].interval && !intervals[i].logged) { 
      log(intervals[i].logVal); 
      intervals[i].logged = true; 
     } 
    } 

    // for last interval 
    if (diff >= intervals[i].interval) { 
     log(intervals[i].logVal); 
     startTime = new Date().getTime(); 
     return; 
    } 

    // Reset Time and run again 
    setTimeout(myLog, 500); 
} 

startTime = new Date().getTime(); 
setTimeout(myLog, 1000); 

這裏的小提琴從ZER0的想法 http://jsfiddle.net/jD8zn/4/

+0

我已經概括瞭解決方案結帳小提琴。 – Ehtesham

0

借款,我會成立一個類似的遞歸超時鏈 -

function startTimeoutChain() { //Represents 1 loop cyele 

setTimeout(function() { 
    log(x); 
    setTimeout(function() { 
    log(y); 
    setTimeout(function() { 
     log(z); 
     startTimeoutChain(); // Begin next loop 
    }, 1000); 
    }, 2000); 
}, 5000); 

} 

只要打電話,一旦&你應該有一些這非常健壯。即使時鐘漂移,這些值也將相互校準,因爲它們基本上是以時間的增量完成的。

雖然說實話,我很難理解你是否想在某個循環週期的第5,7,8秒或者簡單地每5,7,8秒獨立於某個主循環調用它們。

+0

而且,如果我要構建這個,我會誠實地將其設置爲一個函數,它需要3個參數 - 1.主循環長度,2.執行函數的時間數組,3.數組功能。然後在這個函數體中,你可以讓它爲你設置「超時鏈」,而不是自己來安裝這些圖層。如果這是一次性的,可能不值得努力 – jm0

+0

這看起來像我在找什麼。我還沒有真正決定過自己......我想我要設置一個10秒的主循環,並且每個循環的'時鐘'重置爲零。 –

+0

因此,在這種情況下,所有超時應該加起來爲10000(因爲最內層的值代表在執行最後一個函數之後重新開始之前需要等待多長時間,所以您只需將1000增加到3000)。再次,如果它更容易,您可以預先計算這些值。但是因爲這是遞歸的,所以函數的每次運行都代表1個週期......它基本上重置爲0,概念上爲 – jm0

相關問題