我在内部网站上浏览了这个代码段,但我无法理解它:
function safeWrap(f) {
return function() {
setTimeout.apply(window, [f, 0].concat([].slice.call(arguments)));
};
}
稍后,就像这样使用:
// Set click handler.
(...).click(safeWrap(function() { ... } ));
这意味着什么?
答案 0 :(得分:11)
safeWrap返回一个函数,该函数在调用时设置超时0ms(单击事件触发)。
如果safeWrap函数传递的参数多于f,它会将这些参数添加到函数f的参数列表中。
这只是解释所提供的代码。所以我不知道它到底意味着什么......例如,这个代码在哪里使用?
答案 1 :(得分:0)
这样做的一个原因是让点击处理程序在不冻结页面的情况下运行。 JavaScript是单线程的。因此,如果点击处理程序(f
)需要很长时间才能执行(可能正在执行一个需要1分钟的计算),那么该用户在屏幕上执行的任何点击/操作都是{{3} }。单击处理程序完成后,浏览器将执行这些操作。但在此之前,应用程序似乎对用户没有反应 - 他点击按钮,但似乎没有任何事情发生。
setTimeout
会有所帮助,因为点击处理程序会立即返回。回调f
被添加到事件队列中以在将来的转弯处运行,从而使浏览器有机会运行已经存在于队列中的任何事件(例如,被按下并重新启动的按钮动画将具有有机会被处理;如果你有一个长时间运行的点击处理程序,按钮将保持抑制状态)。
虽然这样做更好,但在f
运行时,页面仍有可能被冻结。避免这种情况的方法是f
以小块的形式工作,即做20毫秒的事情,然后用回调调用setTimeout进行剩下的工作。这样,在这20毫秒期间堆积的任何其他事件都有机会运行。这样的功能可能如下所示:
something.click(safeWrap(function() {
function part1() { /* do something */ }
function part2() { /* do something */ }
part1();
safeWrap(part2);
}));
执行此操作的另一个原因是不要让点击处理程序中可能发生的异常冒泡到点击方法。也许,click
方法会自动捕获异常并在屏幕上显示它们,在这种特殊情况下,我们希望错误被忽视。这是因为f
在事件循环的另一个转弯处运行,并且异常不会在堆栈上升到click
,因为调用堆栈在新回合中以f
开头。如果处理程序未包含在click
中,则例外会冒泡到safeWrap
方法,因为在这种情况下,f
将是来自click
的常规方法调用
最后,请注意,即使在安全换行之后,单击处理程序也会获得click
方法传递给它的所有参数。 不获取传递给safeWrap
的其他参数,如其他答案所述。这显然是有道理的,因为我们希望click处理程序不关心处理程序是直接传递还是安全地包装它。这段代码可能很清楚:
(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));
})();