2016-09-24 74 views
4

我在寫一個bot,它以可變間隔發送警報。我正在使用setTimeout(),我有一個問題,我似乎無法弄清楚。 (簡化)的代碼是:連續調用兩次setTimeout()函數

//Original call to setTimeout(): 

timeout = setTimeout(issueAlarm, 2147483647); // highest possible interval setTimeout() will accept. 

//In bot: 
// dh is a priority queue that keeps timestamps sorted from smaller to larger as the user requests alerts. 
//'mom' is a moment.js variable that holds the most recent request. 
//This block of code checks the PQ and if what the user just entered is smaller than what is already stored, it updates the timeout. 
//This seems to work fine 
// First get input from user and store the desired time of first alert in 'mom'. Then: 
var nextD = dh.peekNext(); 
if (nextD.timestamp >= mom.valueOf()){ 
    var now = new Date();   
    clearTimeout(timeout); 
    timeout = mom.valueOf() - now; 
    setTimeout(issueAlarm, timeout); 
    } 

//issueAlarm function: 

function issueAlarm() { 
    var next = dh.getNext(); // this pops the first alarm from the queue 
    // here goes some code that issues message. Then: 
    var peek = dh.peekNext(); // this looks at the next element in the queue without popping it 
    if (peek) { 
     var now = new Date(); 
     timeout = peek.timestamp - now; 
     setTimeout(issueAlarm, timeout); 
     } 
    } 

的例子輸入信號是: 第一輸入中輸入:設置一個警報每8小時從現在開始5分鐘(「呼叫Bob」)

第二輸入輸入:設置從現在起4分鐘開始,每8小時發出一次警報(「致電簡」)

4分鐘後,我正確地獲得了「致電簡」(這一個從機器人代碼設置) 一分鐘後,我正確地得到「打電話給鮑勃「,但我也得到」致電簡「(這應該不會發生,直到8小時後)

我打印所有的超時值,他們似乎是正確的。我還打印issueAlarm()函數內的setTimeout()函數的返回值。

第一次調用內部:_idleTimeout:59994(這是正確的,下一個電話是在一分鐘內)

第二個呼叫內部:_idleTimeout:28739994(這看起來是正確的,這是約8小時,但我仍然立即解決第三個來電)

第三調用內部:_idleTimeout:28799991(此超時看起來正確的,但這個函數調用不應該發生的)

我使用botFramework。我對JavaScript和node.js的知識遠非廣泛。我印出了所有我能想到的東西,但我無法弄清楚爲什麼第三個電話正在馬上做出。

只有當輸入的第一個輸入請求的開始時間晚於在第二個輸入中輸入的開始時間時,纔會發生這種情況。但我不明白爲什麼。

+2

將'timeout'的引用從'setTimeout'改爲'timeout = mom.valueOf() - now;'和'timeout = peek.timestamp - now;''的目的是什麼? – guest271314

+0

在設置新的之前,您沒有清除issueAlarm中的超時,如果有問題的話。另外,您是否確定您爲超時發出的超時間隔值,它們可能比您想象的要短嗎? – Piwwoli

+1

@Piwwoli:我已經嘗試清除超時。它沒有工作。我在這裏打印從setTimeout函數返回的間隔。正如我所說的,在將它們傳遞給函數之前,我還打印了這些值。他們是正確的 – Irene

回答

2

我以爲你可能會遇到Next函數的問題,它返回你的數據,看看我的例子。如果您的函數在保存時返回下一個元素,則無法使用該函數,您需要構建一個返回要調用的第一個鬧鐘的函數。希望能幫助到你!

var dh = {}; 
 
dh.alarms = [{time: 1000, name:"Jane"},{time:5000, name:"Jane"},{time: 3000, name:"Bob"}]; 
 

 
dh.first = function(){ 
 
dh.alarms = dh.alarms.sort(function(a,b){return a.time - b.time}); 
 
next = dh.alarms.slice(0,1); 
 
dh.alarms = dh.alarms.slice(1); 
 
return next[0] 
 
} 
 

 
dh.next = function(){ 
 
next = dh.alarms.slice(0,1); 
 
dh.alarms = dh.alarms.slice(1); 
 
return next[0] 
 
} 
 

 
var timeout = setTimeout(executeAlarm, 2999999); 
 

 
function start(){ 
 
    
 
    var next = dh.first(); // dh.next(); I thought this is your problem!! 
 
    if(next && next.name){ 
 

 
    clearInterval(timeout); 
 
    timeout = setTimeout(function(){executeAlarm(next)},next.time); 
 
    } 
 
    
 
} 
 

 
function executeAlarm(next){ 
 
    if(!next || !next.name) clearInterval(timeout) 
 
    document.getElementById("alarms").innerHTML += "<span> Alarm for " + next.name + "</span>"; 
 
    start(); 
 
} 
 

 
document.addEventListener("DOMContentLoaded", start, false);
<div id="alarms"></div>

+0

感謝您的回覆。但正如我所說(和setTimeout()顯示的返回值),正確檢索元素。警報存儲在優先級隊列中,因此第一個元素總是最小(認爲最小堆和元素正確排序)。同樣,第三個鬧鐘在第二個鬧鐘後立即運行 正如我上面提到的其中一條評論所引起的,我在bot代碼中只調用一次clearTimeout()(而不是每次調用一個新的「更小」元素添加)。這似乎工作,但我仍然不知道爲什麼,我不能真正使用它。 – Irene

+0

看看你的代碼流是這樣的: 1-在1分鐘內清除間隔和setTimeout(簡) 2-從setTimeout調用到1分鐘(Bob) 3-立刻Jane警報再次被觸發。 這是因爲你沒有清理第一次超時。如果您在我的代碼中看到我每次調用啓動函數時clearInterval。 – damianfabian

+1

正如我在上面的評論之一,我已經嘗試在issueAlarm正文中使用clearTimeout(),並沒有改變。 無論如何,只要函數尚未被調用並且您想要更改它,這就是我在機器人代碼中執行的操作,只需調用此函數就不需要清除超時。 在bot代碼中只調用一次clearTimeout()是唯一改變了任何內容的東西。 – Irene

0

(發佈代表OP)的

的問題是在這裏,在機器人代碼:

if (nextD.timestamp >= mom.valueOf()){ 
     var now = new Date();   
     clearTimeout(timeout); 
     timeout = mom.valueOf() - now; 
     setTimeout(issueAlarm, timeout); 
     } 

我正在收拾正確的超時第一次(當我清除了2^31的原超時 - 1),而不是事後。問題是,我呼籲setTimeout的行應該是

timeout = setTimeout(issueAlarm, timeout); 

因此,返回存儲在超時對象。我正在通過傳遞一個值而不是一個對象來進行後續的clearTimeout()調用,因此先存儲的超時(5分鐘,稱爲「Bob」)從未被清除。

感謝@ guest271314和@damianfabian幫助我找到正確的答案。