没有使用jQuery函数会对性能产生什么影响?

4

我在另一个非常相似的主题上发布了一个问题,但结果有点主观。我可以将问题分为两个问题,下面我将解释其中一个:

在以下代码中:

<script type="text/javascript">
$(function() 
{
   $("#accordion").accordion();
   $("#datepicker").datepicker();
   $("#button").click(function() 
   {
     runEffect();
     return false;
   });
});
</script>

问题:如果我在1000个页面中都调用了这段代码,但只有250个页面有一个id为“datepicker”的元素。那么浏览器是否会在其他750个页面上花费额外的时间来解析id为“datepicker”的元素,或者Jquery有一种聪明的方法来解决这种情况而不影响性能?

如果该代码引用了当前页面HTML标记中不存在的ID或类,那么会对性能产生影响吗?


很好,我一直很想知道这个! - Colin
8个回答

7

对于那些说“别担心”的人,我非常不同意。

我曾经建立过一个类似的网站,其中外部JS文件包含有:

$(function() {
  // do lots and lots of stuff
});

在HTML(PHP)页面内部没有JavaScript。这对性能造成了灾难,即使选择器比较高效,也是如此,意味着从未使用:

$(".someClass").doStuff();

取而代之:
$("div.someClass").doStuff();

等等。尽管95%的JavaScript没有做任何事情,但执行所有JavaScript大约需要一秒钟的时间。我的建议是什么?如果你想要一个高度响应的网站,不要这样做

相反,将这样的函数放在你的外部JS文件中:

function activate_accordion() {
  $("#accordion").accordion();
}

当然,这只是一个简单的例子。但关键是:除非绝大多数页面都使用它,否则不应自动执行外部JavaScript文件中的任何JavaScript。您的外部JavaScript文件应该只是一组功能,在需要时在各个页面上调用。
然后在HTML的每个页面上添加以下内容:
<script type="text/javascript">
$(function() {
  activate_accordion();
}
</script>

这样你只会执行实际使用的Javascript。是的,这需要稍微多做一些工作,因为你必须知道每个页面在做什么/使用什么,但是全局执行很快就会失控。

我通过这种方式将Javascript执行时间缩短到了50-100毫秒(从1-2秒)。


让我看看我是否理解你的意思。你在全局包含文件activate_{functionname}中定义函数,然后在使用该函数的标记上添加实际的activate_{functionname}调用。因此,在最后,您与所有activate_{functionname}都有一个合同,并且可以在标记中添加每个页面所需的所有函数。这准确吗? - Geo
就是这样。但是在这个主题上有很多变化。例如,您可以编写一个名为use()或import()的函数,并提供一个常量列表以供页面使用功能。 YUI使用了这种方法,但它也会自动处理依赖项。 - cletus
谢谢提供信息。虽然我不太理解use()和import()的类比,但总体上还是非常感谢。 - Geo

2
它将寻找这样的元素,但由于没有符合条件的,所以它不会执行任何操作。
jQuery的选择器库非常优化性能,所以你不用担心。
特别是,简单的#id选择器会转换为对浏览器本地的getElementById函数的调用,可以认为它非常快。
如果您真的关心性能问题,请在不同的浏览器中进行测试。

2

技术上讲,jQuery会花费一些时间在寻找id为“datepicker”的元素上。

然而,由于您只是通过ID进行选择,并且每个页面仅执行一次,所需的时间可能太小,以至于您无法可靠地测量它。

现在,如果此代码在循环内被嵌套并且将以疯狂的频率执行,则可能需要担心。但这似乎不是这种情况。

这只是小事情,别为此担心。我相信,如果您努力寻找,就可以找到比担心这个更有益的十几个优化方法。


1

这段代码将在每个页面加载时被调用,执行过程如下:

  • $("#accordion").accordion()
    1. 查找匹配的元素:
      1. "#accordion" ID查找非常快
    2. 将函数应用于所有匹配的元素:
      • 如果没有#accordion元素,则会立即返回而不执行任何操作

我认为你只需要在两种情况下关注它:

  1. 您有一个非常复杂的选择器。
  2. 您正在对该元素调用许多函数。

在第二种情况下,这更为常见,我通过以下方式解决:

$el = $('#myElement');
if ($el.length) {
    $el
        .find("div")
        .each(function () { .. })
        .parents()
    // etc...
}

我刚刚编写了一个基准测试来测试这实际上有多大的影响。如果您愿意,可以查看结果代码

简而言之:

// doing this:
var $f = $('#fakeElement');
if ($f.length) $f.find('div');

// is almost twice as fast as this:
$('#fakeElement').find('div');

// For 10000 iterations, 404ms vs 788ms in my tests

没有特别的理由不将其写成一个长链;如果第一部分没有匹配任何内容,那么链就不会继续。例如:$("#myElement").find("div").each(...).parents(),甚至可以写成(在这个例子中)$("#myElement div").each(...).parents()。 - Sixten Otto
链将继续...调用每个函数并返回一个空的jQuery结果集。根据您链接的函数数量,即使是从空集合开始,开销也可能显著增加。 - nickf
@Sixten:请看我刚刚编辑到这个答案中的测试结果……即使只是在一个空集合上执行一个简单的.find,速度也慢得多。 - nickf

1

为什么不混合使用本地调用?

以下每个都运行了10,000次迭代。

$('div#datepicker');
// 179ms

$('#datepicker').find('div');
// 65ms

var $dp = $('#datepicker'); if ($dp.length) $dp.find('div');
// 32ms

if (document.getElementById('datepicker')) $('#datepicker').find('div');
// 1ms

1
jQuery 的部分原因是为了抽象本地实现。getElementById 现在得到了普遍支持,但是多年前,并非每个浏览器都支持它。 - Hollister
1
此外,你的例子并不相等:第一个返回单个元素,而其他的可能会返回多个。 - Hollister

0
如果你有一大块代码依赖于某个元素的存在,你可以随时条件性地执行它。
if( $('#accordion').length > 0 ){
     // 20 lines of #accordion-dependent code here
}

0

$('body').find("#datapicker")...非常快。

我是从核心贡献者那里得到这个建议的。就像这样->

if($("#datepicker")[0]) {...}

但更快。


0

由于jQuery是无状态的,它将不得不查找这个。您可以通过将元素设置为变量并且每当需要时查看您在JavaScript代码中保存的内容,然后只使用该内容来限制影响。

像这样的优化可以帮助解决任何性能问题,尽管如SLaks所提到的,这个调用非常快,但是您可以在不同的浏览器上计时,并查看是否要加速它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接