2010-05-24 40 views
0

TLDR我有一個函數可以在一個openlayers地圖的平底鍋上運行。不要讓它連續發射。運行n秒後延遲運行一次。 (2分鐘的問題)


我有一個函數可以在平移地圖的末尾運行。 我需要它,直到平底鍋結束後3秒纔會開啓功能。儘管我不想排隊這個函數來像setTimeout當前所做的那樣發射10次左右的時間。

如何延遲函數運行n秒,然後只運行一次而不管它被調用了多少次?

map.events.register("moveend", map, function() { 
     setTimeout(SetLocation, 5000); 
    }); 

Moveend:

moveend - triggered after a drag, pan, or zoom completes 

的代碼上述即使使用的setTimeout(FUNC,延遲);運行時仍會多次發射。我怎樣才能防止這一點?


回答

3

好,滿足你的要求,你可以建立一個簡單的函數包裝:

var executeOnce = (function (fn, delay) { 
    var executed = false; 
    return function (/* args */) { 
    var args = arguments; 
    if (!executed) { 
     setTimeout(function() { 
     fn.apply(null, args); // preserve arguments 
     }, delay); 
     executed = true; 
    } 
    }; 
}); 

使用示例:

與您的代碼:

map.events.register("moveend", map, executeOnce(SetLocation, 5000)); 

其他用途:

var wrappedFn = executeOnce(function (a, b) { 
    alert(a + ' ' + b); 
}, 3000); 

wrappedFn('hello', 'world'); 
wrappedFn('foo', 'bar'); // this won't be executed... 

包裝函數將被延遲指定的時間並且只執行一次。

+0

目前未觸發功能。試試你上面發佈的內容。感謝你的快速回復:) /編輯:它正在發射,但是當它發射時,它一次發射約50-60次? – Sphvn 2010-05-24 03:44:44

+0

它正在使用上面的例子仍然導致「SetLocation」函數多次觸發。 – Sphvn 2010-05-24 03:50:59

+0

尾崎,這很奇怪......你確定你只註冊一次'moveend'事件嗎? – CMS 2010-05-24 03:53:41

1

這正是setTimeout的用途。如果setTimeout正在調用這個函數10次,那麼你的代碼有問題,你沒有發佈。

還要記住,setTimeout不會暫停腳本。

2

對於用戶界面延遲,我建議將'clearTimeout'與'setTimeout'結合使用。對'setTimeout'的調用返回一個通常被忽略的ID。但是,如果您存儲該ID,則在下次打算調用「setTimeout」時,您可以取消之前的「setTimeout」(就像您從未調用過它)。

我假設你的情況正在發生的事情是:

(mouse move triggers callback) 
setTimeout (1st) 
(mouse move triggers callback) 
setTimeout (2nd) 
... 
callback from 1st setTimeout is called 
callback from 2nd setTimeout is called 
... 

但是,如果你使用clearTimeout,你必須:

(mouse move triggers callback) 
setTimeout (1st) 
(mouse move triggers callback) 
clearTimeout (1st) 
setTimeout (2nd) 
... 
callback from last setTimeout is called 

要更新您提供的JavaScript代碼:

var delayedSetLocationId = -1; 
... 
map.events.register("moveend", map, function() { 
    if (delayedSetLocationId >= 0) { 
     clearTimeout(delayedSetLocationId); 
    } 
    delayedSetLocationId = setTimeout(SetLocation, 5000); 
}); 
... 
function SetLocation(...) { 
    delayedSetLocationId = -1; // setTimeout fired, we can't cancel it now :) 
    ... 
} 
+0

使用您在上面提供的代碼。它延遲了10-20秒。 然後熄滅了一大堆。我現在唯一能想到的就是它排隊等待OL地圖完成加載它的所有消息。 – Sphvn 2010-05-24 04:41:36

+0

我不確定我是否遵循 - 如果將TimeTime設置爲5000毫秒,如何延遲10-20秒? SetLocation函數應該在上次攔截「moveend」事件後5秒完全調用。我會建議:a)向「moveend」事件處理程序(可從IE開發人員工具/ Firebug/Chrome控制檯等查看)添加一條跟蹤語句,並調查此事件發生的頻率; b)在SetLocation函數中設置斷點並查看調用堆棧以調查誰調用它 – 2010-05-24 04:50:43

+0

還有一件事 - 您可能想要嘗試取消冒泡和處理「moveend」事件,以便您的處理程序指示您注意到並且消耗了事件。 – 2010-05-24 04:52:42

0

我實際上已經寫了一個關於此的小帖子。這很像CMS所建議的。

的代碼片段看起來是這樣的:

var delayonetimeaction = { 

    oneTimeActions: {}, 

    /*** 
    ** Will wait the supplied "delay" until executing 
    ** the supplied "action" (function). 
    ** If called a second time before the with the 
    ** same id, the first call will be ignored and 
    ** instead the second will be used - that is the 
    ** second action will be executed after the second 
    ** supplied delay, not the first. 
    ***/ 
    bind: function (delay, id, action) { 

     // is there already a timer? clear if if there is 
     if (this.oneTimeActions[id]) clearTimeout(this.oneTimeActions[id]); 

     // set a new timer to execute delay milliseconds from last call 
     this.oneTimeActions[id] = setTimeout(function() { 
      action(); 
     }, delay); 

    }, 

}; 

http://sds-digital.co.uk/post/2015/04/21/js-delayed-one-time-action.aspx