Reputation: 1779
I ran across this snippet in an internal web site, but I'm having trouble understanding it:
function safeWrap(f) {
return function() {
setTimeout.apply(window, [f, 0].concat([].slice.call(arguments)));
};
}
Later on, it's used like this:
// Set click handler.
(...).click(safeWrap(function() { ... } ));
What is this meant to do?
Upvotes: 0
Views: 299
Reputation: 1818
One reason this is done to let the click handler run without freezing the page. JavaScript is single threaded. And so, if the click handler (f
) takes a long time to execute (may it is doing a calculation that say takes 1 minute), any clicks/actions the that user performs on the screen are added to a event queue. The browser will perform those actions once the click handler completes. But until then, the app will appear unresponsive to the user - he clicks buttons, but nothing seems to happen.
setTimeout
helps because the click handler returns immediately. The callback f
is added to the event queue to run on a future turn giving the browser a chance to run any events already present in the queue (e.g., the button animation of being pushed down and coming back up will have a chance to be processed; if you have a long running click handler, the button will stay depressed).
While this is better, there is a still a chance that the page would be frozen when f
does get run. The way to avoid this would for f
do its work in small chunks, i.e., do something for say 20 ms, and then call setTimeout with a callback for the rest of the work. This way, any other events that piled up during those 20 ms would have a chance to run. Such a function might look as follows:
something.click(safeWrap(function() {
function part1() { /* do something */ }
function part2() { /* do something */ }
part1();
safeWrap(part2);
}));
Another reason to do this would be to not let an exception that might happen in the click handler bubble up to the click method. Perhaps, the click
method automatically catches exceptions and shows them on the screen, and in this particular case, we want the error to go unnoticed. This works because f
is running on a different turn of the event loop, and exceptions will not go up the stack to click
because the call stack starts with f
in the new turn. The exception would bubble up to the click
method if the handler is not wrapped in safeWrap
because in that case, f
would be a regular method call from click
Lastly, note that that the click handler even after safe wrapping gets all the arguments that the click
method passes to it. It does not get the additional arguments passed to the safeWrap
as pointed out in the other answer. This obviously makes sense because we want the click handler to not care if handler is passed directly or with it safely wrapped. This code probably makes it clear:
(function() {
console.clear();
function safeWrap(f) {
return function() {
setTimeout.apply(window, [f, 0].concat([].slice.call(arguments)));
};
}
var f = function(a) { console.log(a /* prints 2 */); throw Error("f"); };
function click(f) {
f(2);
}
click(safeWrap(f, 1));
})();
Upvotes: 0
Reputation: 1815
safeWrap returns a function that sets a timeout of 0ms when called (click event fired).
If the safeWrap function is passed more arguments than f, it will add these to the argument list of function f.
Thats just interpretation of the code provided. So I can't tell what it really is meant to do... Where is this code used, for example?
Upvotes: 11