Requirejs domReady插件与Jquery $(document).ready()有何区别?

105
我正在使用RequireJS,并且需要在DOM就绪时初始化某些内容。现在,RequireJS提供了domReady插件,但我们已经有了jQuery的$(document).ready(),由于我已经要求了jQuery,它也对我可用。
因此,我有两个选项:
  1. Use the domReady plugin:

    require(['domReady'], function (domReady) {
        domReady(function () {
            // Do my stuff here...
        });
    });
    
  2. Use $(document).ready():

    $(document).ready(function() {
        // Do my stuff here...
    });
    

我应该选择哪个,为什么?

两个选项都能正常工作。我不太确定jQuery的选项是否可靠,因为RequireJS会发挥其魔力;也就是说,由于RequireJS将动态添加脚本,我担心DOM准备好之前可能会加载所有动态请求的脚本。而且,当我已经需要jQuery时,RequireJS会增加额外的JS负担,只为了domReady

问题

  • 为什么RequireJS提供了一个domReady插件,当我们可以使用jQuery的$(document).ready();?我看不出包含另一个依赖项的任何优点。
  • 如果只是为了满足需求,那么为什么不为跨浏览器AJAX提供一个呢?

据我所知,需要domReady的模块在文档准备好后不会被获取或执行,你也可以同样需要jQuery:

require(['jQuery'], function ($) {
    $(document).ready(function () {
        // Do my stuff here...
    });
});

为了更清楚地阐述我的问题:需要domReady还是需要jQuery有什么区别?

4
我对jQuery的dom ready不够自信。我想用“:p”标记它为冒犯的。 - Dakait
3
jQuery的DOM就绪事件在IE上也非常可靠。数百万人每天使用它而不知道;-) - John Dvorak
1
你是否控制着script标签的位置,或者你正在编写一个其他人将使用的库/插件(因此他们控制标记中script标签的位置)? - T.J. Crowder
基本上domContentLoaded是关键。你可以使用JavaScript来挂钩它。http://ablogaboutcode.com/2011/06/14/how-javascript-loading-works-domcontentloaded-and-onload/. 我想知道为什么你不相信Jquery?Jquery通过访问domContentLoaded也可以做到同样的事情。 - Ravi Gadag
3
上帝啊……请结合全文阅读。"我对jquery的dom ready不太有信心,因为requirejs正在发挥其作用。" 因为require将jquery封装在有限的本地作用域中。那不是重点(就问题而言)。 - Yugal Jindle
5个回答

95

看起来所有的关键点都已经提及了,但一些细节被忽略了。主要是:

domReady

它既是插件又是模块。如果你在需求数组中包含它并带有一个结尾的!,你的模块将不会执行,直到可以安全地与DOM交互为止:

define(['domReady!'], function () {
    console.info('The DOM is ready before I happen');
});
请注意,加载和执行是不同的;您希望尽快加载所有文件,但时间关键的是内容的执行。 如果省略了 !,那么它只是一个普通模块,恰好是一个函数,可以接受一个回调函数,在DOM安全进行交互之前不会执行:
define(['domReady'], function (domReady) {
    domReady(function () {
        console.info('The DOM is ready before I happen');
    });
    console.info('The DOM might not be ready before I happen');        
});

使用domReady作为插件的优势

依赖于一个又依赖于 domReady! 模块的代码有一个非常显著的优势:它不需要等待DOM准备就绪!

假设我们有一段代码A,它依赖于一个模块B,而模块B依赖于domReady!。在DOM准备就绪之前,模块B将无法完成加载。转而说,A将在B加载完成之前不会运行。

如果您要将domReady用作B中的常规模块,则还需要A依赖于domReady,并将其代码包装在domReady()函数调用中。

此外,这意味着domReady!$(document).ready()相比享有同样的优势。

关于domReady和$(document).ready()的区别

两者都以基本相同的方式检测DOM是否已准备就绪。

关于担心jQuery在错误的时间触发

即使DOM在jQuery之前加载,jQuery也会触发任何就绪回调(您的代码不应该关心哪个先发生)。


2
美丽,这正是我所寻找的。合理,得到了很好的支持。 - Yugal Jindle
@YugalJindle 赏金任务有什么遗漏吗? :) - fncomp
我只是在测试你写的东西 - 给你! - Yugal Jindle
当我使用感叹号时(例如http://dpaste.com/182FH3B),我会得到以下错误:`Uncaught TypeError: domReady不是函数`。 - nnyby
那个链接指向一个部分粘贴。你不应该使用domReady插件的返回值。domReady插件会保持你的模块的解析,直到至少DOMContentLoaded,它没有其他有用的功能。 - fncomp
显示剩余2条评论

20
尝试回答你的主要问题:
为什么在我们可以使用jquery的$(document).ready()时,requirejs提供了一个domReady插件?
实际上,它们是两种不同的功能。RequireJS的domReady依赖表示该模块需要在完全加载DOM之前才能运行(因此,如果您愿意,可以在应用程序中的任何数量的模块中找到它),而$(document).ready()则在DOM加载完成后触发其回调函数。
这个区别可能看起来很微妙,但请考虑以下情况:我有一个需要以某种方式与DOM耦合的模块,因此我可以依赖于domReady并在模块定义时进行耦合,或者在最后放置一个$(document).ready(),并带有指向该模块的init函数的回调。我会称第一种方法更加简洁。
同时,如果我有一个需要在DOM准备好的时候立即发生的事件,那么$(document).ready()事件就是最佳选择,因为它不特别依赖于RequireJS完成加载模块,只要您调用它的代码的依赖项得到满足即可。
还值得考虑的是,并不一定需要使用jQuery和RequireJS。任何需要DOM访问(但不依赖于jQuery)的库模块仍然可以通过使用domReady来实现。

1
非常好的答案,也是许多开发人员经常没有意识到的微妙提示(包括我自己;-))。 - Golo Roden
1
Yugal,我提到domReady作为依赖项,因为它是这样使用的。不是RequireJS的依赖项,而是在使用它的模块的依赖项。也许我应该在我的文本中更清楚地表达这一点,你有什么建议吗? - Gert Sønderby
Yugal,如果你使用MooTools?Qooxdoo?任何不是jQuery的东西?RequireJS并没有和jQuery捆绑在一起,尽管它们确实能很好地一起工作。 - Gert Sønderby
好的,我不知道你所说的“满足需求”的评论是什么意思。我猜我不能帮助你回答这个问题。但请注意,你不要只是在寻找对你不喜欢的特定代码的抨击。对你来说愚蠢和无用的东西可能会拯救另一个人的项目。 - Gert Sønderby
没问题。如果我找到一个合理的解释,我会回来的。谢谢。 - Yugal Jindle
显示剩余4条评论

6

按顺序回答你的问题:

  • 它们两者都可以实现相同的功能
  • 如果你有关于使用 jQuery 的任何疑虑,那么使用 domReady
  • 正确,所以只需使用 jQuery
  • 因为并不是每个人都使用 jQuery
  • 我同意,只需要使用 jQuery
  • 插件根据定义“满足需求”。
  • 跨浏览器 Ajax 不是一个事情。跨域?可能会有,如果没有,那么就没有必要添加。
  • ,-,-,- 好的

归根结底,你在过度思考这个问题。这只是一种执行 JavaScript 的机制,在 DOM 加载完成后立即执行。如果你没有 jQuery,我会推荐 domReady 插件。既然你已经有了 jQuery,就不要加载更多脚本来做已经可用的事情。

更新:

domReady 插件集合函数,当文档准备就绪时调用这些函数。如果已经加载,则立即执行。

JQuery 收集函数并绑定deferred 对象到准备好的 DOM 上。当 DOM 准备就绪时,deferred 对象将被解决并执行函数。如果 DOM 已经准备就绪,则 deferred 对象已经解决,因此该函数将立即执行。

这意味着它们实际上完全相同。


0

在尝试使用多个模块的requirejs后,我建议使用 domReady

我注意到当requirejs加载多个模块时,与$(document).ready(...)相关联的函数不会被调用。我怀疑dom在所有requirejs代码执行之前已准备就绪,并且jquery ready回调处理程序在它与用户定义的函数即主模块代码绑定之前被调用了。

require(['jquery',
    'underscore',
    'text!some_template.html',
    './my_module_1',
    './my_module_2',
    'domReady',
    'other_dependency_1',
    'other_dependency_2'
    ], function($, _, someTemplate, myModule1, myModule2, domReady) {

    $(document).ready(function() {
        console.info('This might never be executed.'); 
        console.info('Dom might get ready before requirejs would load modules.');
    });

    domReady(function () {
        console.info('This runs when the dom gets ready and modules are loaded.');
    });
});

1
我怀疑一旦你在依赖列表中包含了所有模块,它们都将被获取并加载到内存中。在此之后,jQuery会在执行前收集dom.ready实例。 - Yugal Jindle
如果DOM已经准备就绪,$(document).ready的回调函数将立即运行。 - Danyal Aytekin

-1

我发现将此作为主入口的一部分来执行,以确保所有的JavaScript都已准备就绪并且jQuery已加载。不确定这是否很好,欢迎任何反馈,以下是我的main.js:

require(['domReady!'], function(domReady){
    console.log('dom is ready');
    require(['jquery', 'bootstrap'], function(){
        console.log('jquery loaded');
        require(['app'], function(app){
            console.log('app loaded');
        });
    });
});

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