Delay function from running for n seconds then run it once. (2minute question)
TLDR I have a function that runs on the end of a pan in an openlayers map. Don't want it to fire continously.
I have 开发者_如何学Ca function that runs on the end of panning a map. I want it so that it will not fire the function until say 3 secconds after the pan has finished. Although I don't want to queue up the function to fire 10 or so times like setTimeout is currently doing.
How can I delay a function from running for n seconds then run it only once no matter how many times it has been called?
map.events.register("moveend", map, function() {
setTimeout(SetLocation, 5000);
});
Moveend:
moveend - triggered after a drag, pan, or zoom completes
The code above even using setTimeout(func, delay); still fires multiple times when it runs. How can I prevent this?
Well, meeting your requirements, you could build a simple function wrapper:
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;
}
};
});
Usage examples:
With your code:
map.events.register("moveend", map, executeOnce(SetLocation, 5000));
Other usages:
var wrappedFn = executeOnce(function (a, b) {
alert(a + ' ' + b);
}, 3000);
wrappedFn('hello', 'world');
wrappedFn('foo', 'bar'); // this won't be executed...
The wrapped function will be delayed the specified amount of time and executed only once.
For UI delays I would recommend using 'clearTimeout' in conjunction with 'setTimeout'. A call to 'setTimeout' returns an ID that is usually ignored. If, however, you store the ID, next time you are about to call 'setTimeout' you can cancel the previous 'setTimeout' (as though you never called it).
What I assume is happening in your case is:
(mouse move triggers callback)
setTimeout (1st)
(mouse move triggers callback)
setTimeout (2nd)
...
callback from 1st setTimeout is called
callback from 2nd setTimeout is called
...
If, however, you use clearTimeout, you'll have:
(mouse move triggers callback)
setTimeout (1st)
(mouse move triggers callback)
clearTimeout (1st)
setTimeout (2nd)
...
callback from last setTimeout is called
To update the JavaScript code you provided:
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 :)
...
}
This is precisely what setTimeout is for. If setTimeout is calling the function 10 times, there's something wrong with your code, which you didn't post.
Also keep in mind that setTimeout will not halt the script.
I have actually written a small post about this. It is mush like what CMS has suggested.
The code snippet looks like this:
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
精彩评论