【问题标题】:How do you organize large JS/jQuery code bases across your entire website?您如何在整个网站上组织大型 JS/jQuery 代码库?
【发布时间】:2010-09-08 14:05:26
【问题描述】:

您如何在整个网站上组织大型 JS/jQuery 代码库?有很多关于如何组织代码片段的好资源,但没有真正关于如何将它们组合在一起并将每个片段放置到位:横向代码组织,使用相同代码的多个页面,保持 DRY 松散耦合,等等

以下是我的处理方法。我从来没有习惯像这样组织我的代码,因为我认为它很草率并且可能导致可维护性/可扩展性问题,但我真的不知道更好。

我意识到我每个人都有自己的一套要求,并且没有统包解决方案,但我很想听听一些关于我做错了什么、为什么我做错的意见,以及关于如何做的建议编写更易于维护的代码。

我认为我真正想要达到的目的:

  1. 你如何处理你的逻辑 需要在多个地方使用,在 多页?

  2. 如何组织特定页面 代码?将每个页面命名为 全局对象是个好主意吗?1.

  3. 你从一开始做什么 确保你不会经常 重写你的组织 应用程序变大时的模式 和更大?我可能在我的 4th 迭代写这个东西。2.

每个页面都接收到主 application.js 文件。每个附加页面都有自己的 application.pagename.js 文件。我使用服务器端逻辑来包含文件(首先检查以查看 如果该页面甚至存在一个 - 有些页面不需要 JS),然后按顺序初始化它们。

所以我的主页看起来像:

<script src="js/application.js"></script>
<script src="js/application.index.js"></script>
<script>
    MyApp.init();
    MyApp.index.init();
</script>

我的 URL 约定是 /page/subpage/id/。我有大约 10 页和一大堆子页面,每个子页面都需要自己的逻辑。请参阅本文中的最后一个示例。

我的大部分代码已经模块化为 jQuery UI 小部件或 jQuery 插件,所以我想说这些文件中 75% 的代码是 require()'ing 一个小部件并对其进行初始化。

我根据需要使用 requireJS 来拉入小部件。

// application.js
var MyApp = {
    init: function(){
        var self = this;

        // these widgets are available on every single page
        // notice the call to jquery.deparam.js - i'll use this later to init subpage logic.
        require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){

            // deparam the query string.  I'll use this later.
            self.querystring = $.deparam.querystring();

            // init widgets once the document is ready
            $(function(){
                $("#widget1").widget1();
                $("#widget2").widget2();

                // make these bindings available immediately as well.
                self.rebindable();
            });
        });
    },

    // I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded
    // via an AJAX request.  I'll call this method after each AJAX request to
    // rebind some key widgets.
    rebindable: function(){
        $("#widget3").widget3();
    }
};

// application.index.js
// home page specific stuff.  this file is only included on the home page.
MyApp.index = {

    // my convention is that init is automatically called after the script
    // is included in a page, outside of a doc.ready statement.
    init: function(){
        var self = this;

        require(['js/widget4.js'], function(){
            $(function(){
                self.widget4( $("#foo") );
            });
        });
    },

    // passing elements to each method allows me to call this init code
    // outside of the index page.  I can require() this file, and only init
    // widget4, and even use a different element.
    widget4: function( element ){
        var config = {
            something: "custom to the home page"
        };

        element.widget4( config );
    }
};


// application.foo.js
// page "foo" stuff
MyApp.foo = {

    init: function(){
        var self = this;

        // this page happens to use the same widget3 and configuration present 
        // in MyApp.index.  this is where things can get sloppy and unmaintainable
        // really quickly.
        require(['js/application.index.js'], function(){
            $(function(){
                MyApp.index.widget3( $("#bar") );
            });
        });

        // page "foo" has three subpages (or actions) and require
        // their own logic.  url convention:  /foo/subpage1/
        // init whichever page we're on...
        switch( self.querystring.subpage ){
            case "subpage1":
                self.subpage1.init();
                break;
            case "subpage2":
                self.subpage2.init();
                break;
            case "subpage3":
                self.subpage3.init();
                break;
        }
    },

    subpage1: function(){
        init: function(){
            var self = this;

            // once the DOM is ready init dialog.
            $(function(){
                self.dialog( $("#openDialog") );
            });
        },

        dialog: function( element ){
            element.bind("click", function(){
                $('<div></div>').dialog({
                    open: function(){

                        // see what i'm doing here?
                        MyApp.rebindable();

                        // maybe more bindings specific to this
                        // dialog here
                    }
                });
            });
        }
    },

    subpage2: function(){
        init: function(){
        }
    },

    subpage3: function(){
        init: function(){
        }
    }
};

【问题讨论】:

  • 这周我自己也在考虑这个问题。我最近加入了一个项目团队,担任主要的 javascript 编码员。该项目已经进行了一年多,所以他们到处都有 javascript。他们积累了大量的 javascript 库,并在使用命名空间方面做出了一些努力,但是很多页面都有自定义的 javascript,这些 javascript 不仅是在页面和用户控件中编写的,还有一些是基于页面或用户控件数据生成的。我的艰巨任务是理解这一切并尽可能地标准化。
  • (续)您的方法是一个好的开始,但我可以看到它无法维护的地方。也许您可以设计一种配置页面和控件的方法,这样您就不必使用很多 switch 语句。您还可以查看 Claypool (http://www.claypooljs.com) 看看是否有帮助。
  • @Silkster 链接已损坏:http//www.claypooljs.com
  • 貌似移到了 jQuery 网站:docs.jquery.com/Plugins/Claypool

标签: javascript jquery


【解决方案1】:

为了帮助我回答您的具体问题,请允许我谈谈JavaScriptMVC 的功能:

Controller 将改进您的 jQuery 小部件,负责设置/拆卸、可扩展性。

View 添加可内置到您的应用中的客户端模板。

模型抽象了服务/数据层,如果您的服务器发生更改,则最小化和本地化 JS 更改。

Steal 进行依赖管理、压缩和代码清理。它甚至会在所有页面中获取所有脚本,找出共享依赖项,并将脚本组合成最佳负载。

FuncUnit 让您的应用测试变得尽可能简单。

DocumentJS ...好吧...记录您的代码

.

现在谈谈您的具体问题:

如何处理多处使用的逻辑?

我使用 StealJS 的依赖管理系统将我需要的功能加载到我的页面中。对于一定规模的应用程序,依赖管理是绝对必要的。如果您能够轻松构建 RequireJS 是一个不错的选择。

你如何组织页面特定的代码

页面特定代码应尽可能小。它通常涉及加载依赖项和“MainController”。该主控制器配置页面以遵守该页面的功能/业务要求。它通常被命名为:

App.Controllers.Main

你如何停止编写相同的模式

好吧,我建议使用具有稳定开发模式的框架。此外,让您的模块/插件/小部件尽可能小(且可测试)。这将使这些部分发生变化的可能性大大降低。

终于......

看来你最大的矛盾是:

  • 共享功能
  • 多页
  • 及时加载时间

因此,选择可靠的依赖管理工具非常关键。 StealJS 可以帮助您获得最佳的加载时间,但由于您的页面数量较多,您不得不偏离 JavaScriptMVC 的标准文件夹组织。

RequireJS 更灵活,但您将不得不加载大量文件。这不仅会很慢,而且会开始让你创建很多没有组织的大 JS 文件。

如果您对加载时间感到满意,并且觉得它们不会导致您将代码压缩到它不属于的文件中,那么您当前的解决方案似乎可以工作。

我认为可维护开发的秘诀在于您的系统/框架让您能够轻松地隔离关注点。将您的应用程序分解为尽可能小的部分非常重要。另外,您应该测试这些部分。人们在考虑他们的页面功能时会偏离轨道。但要真正扩展开发规模,您确实需要能够将应用分解成小部分、轻松加载这些部分并以某种方式让应用在生产环境中仍能快速运行的东西。

【讨论】:

  • 澄清一下:RequireJS 可能会在开发过程中加载单个文件,但它有一个优化工具 (requirejs.org/docs/optimization.html),允许您将模块优化/分组为一小组 HTTP 请求。优化工具也可以在 dev 中使用,它有一种方法可以只排除您可能想要自己调试的某些模块。
  • 是的,这是我的错误。 RequireJS 可以组合所有的脚本。但我不认为它可以在多个项目之间进行窃取自动中断。
  • "该主控制器配置页面以符合该页面的功能/业务要求。"所以 Controller 是这里逻辑的主要驱动器,而不是鼓励将业务逻辑保留在 Model 中的服务器端编程?
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2014-06-14
  • 2015-02-04
  • 2011-04-16
  • 2010-10-17
相关资源
最近更新 更多