1

我工作过的大多数支持 jQuery 的 Web 应用程序都以两种方式之一来组织 document.ready 逻辑。

  1. 全局 document.ready 用于站点范围的 JS 文件,所有 document.ready 逻辑都包含在该执行块中。
  2. document.ready 逻辑被显式添加到需要它们的特定页面。

通常,我选择选项 1,以便 javascript 享受 javascript 合并和缩小的好处,这些好处很容易应用于独立文件而不是页面上的 javascript 块。

但是,随着站点的增长,需要在 document.ready 处执行的逻辑量也会增加,我怀疑正在评估的选择器数量会影响站点的快速性。

我已经考虑为此开发一个框架,从而可以应用一种全局技术,该技术使用 URL 或根元素属性来确定应该在 document.ready 上执行哪些代码并减少正在评估的选择器的数量。

编辑:更多澄清...... 在一个简单的例子中,我有 2 个不同的页面。在每个页面上,逻辑(包括选择器)需要在 document.ready 上执行,但理想情况下,逻辑仅在加载这些页面时执行,而不是在整个站点的每个页面上执行。

这样的东西是否已经存在,或者选择器通常足够便宜以至于我不应该关心?

4

5 回答 5

0

首先,我主要使用单页应用程序。

我通常是这样操作的:

// Main module
;(function($, win, undefined) {
    var module = {
        _currentPanel,
        initialize: function() {
            // all my global bindings here
        },

        // Only included to understand whats going on in the sub-module below
        displayPanel: function(panelName) {
            if (!!module._currentPanel) {
                $(module._currentPanel)
                    .hide(0)
                    .triggerHandler('hide.panel');
            }

            module._currentPanel = panelName;

            $(panelName)
                .show(0)
                .triggerHandler('show.panel');
        },          
    };

    $.extend("namespace", module);
})(jQuery, window);



// Sub modules
;(function($, win, undefined) {
    var module = {
        something: function() {
            // ..nothing to see here, this is just how i construct my modules
        }
    };


    // Event bindings specific to this module
    $('#geo-panel').bind('show.panel', function() {
        // wire up init() stuff   
    });
    $('#geo-panel').bind('hide.panel', function() {
        // wire up dispose() stuff
    }); 

    $.extend("namespace", module);
})(jQuery, window);

那么那里发生了什么?

我的主模块包含所有全局内容..这是合乎逻辑的 :) 使用我在加载页面时在某处调用的 initialize() 函数。这连接了我在所有页面(或本例中的视图)上有用的所有通用绑定/选择器。

然后,当我在应用程序中显示各种伪页面时,我的子模块将绑定到我触发的事件。他们都对 .triggerHandler() 做出反应,我使用了很多来能够在整个站点中分离我的逻辑。

displayPanel("#geo-panel");

displayPanel("#someother-panel");

然后将主模块和子模块都聚合成一个大的 js 文件。这里有一些多余的 $.extend() (我用它来动态创建命名空间),它允许我将所有内容拆分为自动构建的专用子模块(首选项、配置文件、搜索......)在应用程序构建时聚合。

但是,如果我没有使用单页应用程序,那么我会:

  1. 只需将所有引用从#panel-geo, 更改为更像#pageX #panel-geo
  2. 或为所有页面选择 1 个通用 js,为每个页面选择 1 个特定 js
于 2012-12-16T23:13:16.010 回答
0

我一直在使用你在我最新项目中描述的东西。我给每个页面中的 HTML 标记一个唯一的 ID,然后我用它来初始化特定于该页面的代码:

$(function() {
    //for index.html (view/edit)
    if($("html#view").length>0){
        ReadView();
    }
    //for create.html (add)
    if($("html#create").length>0){
        CreateView();
    }
    globalFunction();
});

var ReadView = function(){
    ...
};

var CreateView = function(){
    ...
};

var globalFunction = function(){
    ...
};

正如您所说,这不仅有助于保持 JavaScript“活泼”,而且有助于命名间距并有助于防止变量冲突。我还发现,当其他程序员查看代码时,它有助于以更有条理的方式理解事物。

于 2012-12-11T16:42:19.597 回答
0

组织页面的替代方法可能是用户 jquery 的 triggerHandler 来“拆分” document.ready事件,如下所示:

准备就绪:

$(namespace.eventPool).triggerHandler("namespace.preready");
$(namespace.eventPool).triggerHandler("namespace.domready");
$(namespace.eventPool).triggerHandler("namespace.postready");

从 ajax 加载的模板(示例):

$(namespace.eventPool).triggerHandler("namespace.templates.loaded");

伪代码中的示例用法:

function loadTemplates(){
    $.get...
    $(namespace.eventPool).triggerHandler("namespace.templates.loaded");
}

$(namespace.eventPool).on({
   "namespace.preready":loadTemplates,
   "namespace.templates.loaded":invalidateCache
});

等等

这样做的目的是避免一次猛烈抨击所有内容,而只使用少量基于事件的 pub/sub

于 2014-01-31T14:40:53.740 回答
0

我所做的是拥有两组(虽然可能更多)文件。一个 app.js 文件,其中包含站点的全局内容,每个页面的 page.js 文件都包含该页面特定的内容。

page.js 文件设置了一个对象,即对象,该myapp.page对象包含特定于该页面但与具有全局上下文的事物相关的功能。该文件还包含特定于该页面且与任何全局内容无关的内容。

典型的 page.js 看起来像这样:

var myapp = mayapp || {};
myapp.page = {
    onReady: function($, undefined) {
        // page specific initialization that will need to use
        // things initialized in the global initialization
    },

    // for other events that I want some page-specific behavior 
    // in addition to the global behavior. For example, onresize:
    onResize: function(e, anything) {
        // page specific response to some event
        // that uses or relies on things done in the global
        // onresize listener
    }
}

// stuff that is page specific that is completely autonomous.
// This could also be included in the myapp.page.onReady, if preferred.
// I like the seperation because it illustrates what on the page 
// depends on global resources.
$().ready(function() {
    $('#some-form').submit(function(e) {
        // the form only exists on this page so no need to put it in
        // the page.onReady callback function
    });
});

app.js 文件使用 $().ready(...) 来完成页面加载。然后它调用页面特定的 JS:

$().ready(function() {

    var myapp = mayapp || {};

    // do global stuff first
    globalStuff();
    // then page specific
    if (myapp.page && typeof myapp.page.onReady === 'function') {
        myapp.page.onReady($);
    }

    // if there are some events that have both global page specific things
    // going on I would have something like this:
    window.addEventListener('resize', function(e) {
        // global behavior
        someResult = processedTheSameOnAllPges();

        // then page specific
        if (myapp.page && typeof myapp.page.onResize === 'function') {
            myapp.page.onResize(e, someResult);
        }
    });
})

我以这种方式将事情分开主要是为了简化,但它肯定会对大型网站产生性能影响。这确实有单独文件的缺点,因此将有两个下载。但是,每个页面都只是在下载和执行它需要的东西。

关于性能,如果由于选择器而导致初始化缓慢,则可以考虑将它们中的一部分或全部本地化。

对于特定数据,特别关注选择器(在 OP 中多次提到),我能提供的最好的是一些有趣的 jsPerf 案例:

恕我直言,这些测试的一个巨大限制是他们使用的“准备代码”。这些测试场景是不现实的,据我所知,运行选择器的 DOM对其性能有巨大影响。

于 2012-12-17T06:07:55.457 回答
-1

每个页面都“知道”需要在该页面上执行哪个 JS。因此,在您的 .js 文件中定义这些函数,并在 HTML 标记中进行 doc-ready 调用以仅调用这些函数。

虽然您应该避免在 HTML 中放置重要的 JS 代码,但调用一两个 init 函数是完全可以接受的。

于 2012-12-11T19:41:39.033 回答