这个Javascript代码有什么作用?

时间:2009-06-21 12:04:31

标签: javascript

我在内部网站上浏览了这个代码段,但我无法理解它:

function safeWrap(f) {
  return function() {
    setTimeout.apply(window, [f, 0].concat([].slice.call(arguments)));
  };
}

稍后,就像这样使用:

// Set click handler.
(...).click(safeWrap(function() { ... } ));

这意味着什么?

2 个答案:

答案 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));

})();