跳到主要内容

如何使您的网络应用程序表现更好

随着每年的过去,开发人员进一步深入到JavaScript重型网站和应用程序的新世界。使用像jQuery这样的代码库和Backbone.js或Ember.js这样的框架,以及可重复使用的插件的瑞士军刀,可以简化JS开发的核心方面,以便让我们能够建立更丰富的用户体验既有用又有乐趣。

我们添加到项目中的每个JavaScript文件都会带来额外的复杂性,特别是在我们如何管理该文件与代码库中其余JS文件的关系方面。我们可以在一个文件中编写一些代码,使用来自单独文件的jQuery插件与页面进行交互,而jQuery插件又依赖于jQuery存在并从另一个文件加载。

随着项目规模的增长,文件之间可能的连接数也会增加。我们说任何需要另一个文件才能正常运行的JavaScript文件都依赖于该文件。

The RequireJS homepage contains the library files plus plenty of documentation and examples to help you learn more after finishing this tutorial

RequireJS主页包含库文件以及大量文档和示例,可帮助您在完成本教程后了解更多信息

管理风格

大多数情况下,我们以线性和手动方式管理我们的依赖项。在我们的HTML文件的末尾,在结束之前我们通常按顺序列出我们的JavaScript文件,从最通用的库和框架文件开始,然后处理大多数特定于应用程序的文件。我们需要确保每个文件在其依赖项之后列出,以防止在尝试访问尚未加载的其他脚本文件中定义的变量时出错。

随着文件数量的增加,这种依赖管理方法变得越来越难以维护,特别是如果您希望删除文件而不影响依赖它的任何其他代码。

需要一种更健壮的方法来管理更大的网站和应用程序中的依赖关系。本教程将解释如何使用RequireJS这样做,这是一个为解决这个问题而创建的JavaScript模块加载器,它具有按需脚本文件加载的附加优势。

The BBC is a proponent of RequireJS and has its own documentation site for their developers to refer to when building JavaScript modules

BBC是RequireJS的支持者,并且有自己的文档站点供开发人员在构建JavaScript模块时参考

RequireJS库基于异步模块定义(AMD)API,这是一种定义代码块及其依赖关系的跨语言统一方法,在业界获得了很大的关注(它在BBC,Hallmark等网站上使用) ,Etsy和Instagram,以及其他)。

让我们首先创建一个简单的HTML页面,将其命名为index.html,并在其中编写一个非常简单的表单,将电子邮件地址发布到名为thank-you.html的单独页面。我会让你自己创建这个页面 - 或者你可以下载一个例子,以及一些示例CSS样式,来自教程zip文件包

邮件列表

加入我们的邮件列表

在我们继续前进之前,让我们来吧下载RequireJS的副本。 (在撰写本文时,该库的当前版本为2.1.4,并且在所有主要Web浏览器中都支持它返回到Internet Explorer 6,Firefox 2,Safari 3.2,Chrome 3和Opera 10.)

现在,在我们将RequireJS添加到页面之前,让我们回顾一下我们应用程序需要哪些JavaScript文件,并将它们组织到适当的文件夹结构中。

The final page we're building represents a newsletter sign-up form, which will only submit if the email address provided is in a valid format

我们正在构建的最后一页代表一份简报注册表单,只有在提供的电子邮件地址格式有效时才会提交

我们将从我们的主应用程序脚本文件开始,使用jQuery,它将侦听HTML表单上的提交事件并在发生这种情况时执行表单验证,只允许表单在没有错误的情况下继续提交。因此,除RequireJS外,我们还有三个JavaScript文件:

  • 最新版本的jQuery(jquery-1.9.0.js)
  • 表单验证脚本jQuery插件(validation-plugin.js)
  • 我们的主要应用程序脚本文件(main.js)

让我们将这些文件和RequireJS以及教程的其余文件一起安排到合理的文件夹结构中:

-index.html
- 谢谢,you.html
-styles /
-main.css(添加自己的CSS文件)
-scripts /
-require.js
-main.js
-lib /
-jquery-1.9.0.js
-validation-plugin.js

请注意,我们已将所有JavaScript文件放在一个脚本文件夹中,并将RequireJS与主应用程序脚本文件一起放在此文件夹的根级别。所有其他可重用的第三方脚本一起存储在lib子文件夹中。

启动并运行

通过添加一个来加载RequireJS并在HTML页面上进行设置

请注意,就像我们的data-main属性一样,在引用任何带有RequireJS的文件时,可以排除.js文件扩展名,因为它默认采用此扩展名。

The developers of jQuery added support for RequireJS. No special code is required to use it as a dependency in your modules

JQuery的开发人员添加了对RequireJS的支持。将它用作模块中的依赖项不需要特殊代码

使用Require方法使用RequireJS定义可重用的代码块或模块,该方法遵循以下模式:

define(moduleName,//可选,默认为文件依赖项的名称,//列出此文件的依赖项函数的可选数组(params){//一旦加载了依赖项就执行的函数// params包含来自依赖项的返回值});

在对define方法的调用中需要出现的所有内容都是包含模块代码的函数。通常,我们会为代码库中的每个模块创建一个单独的文件,默认情况下,模块名称将通过其文件名在RequireJS中标识。

如果您的代码依赖于其他代码才能正常运行(例如,jQuery插件需要jQuery),那么您应该在函数参数之前的define方法中的数组中列出这些所谓的依赖项。要在此数组中使用的名称通常对应于相对于RequireJS库文件本身位置的依赖项的文件名。

在我们的示例中,如果我们想将jQuery列为另一个模块的依赖项,我们会将它包含在依赖项数组中,如下所示:

define([“lib / jquery-1.9.0”],function($){});

我们不需要指定文件扩展名,因此我们在列出依赖项时不要这样做。顺便提一下,如果页面上出现这种情况,jQuery的最新版本包含使用define方法将自身注册为模块的代码,因此我们不需要编写任何特殊代码来将jQuery库转换为我们需要与RequireJS一起使用的格式。

依赖脚本提供的任何返回值都通过输入参数传递给模块功能代码本身。只应在此模块中使用传递给此函数的这些参数,以便正确封装代码及其依赖项。

我们现在有办法编写模块代码与其所依赖的代码之间的关系。正是这种关系告诉RequireJS在执行该函数之前加载模块函数所必需的所有代码。

让名字正确

我们知道jQuery有一个约定包含版本号的文件的约定,如上所述。如果我们有很多引用(在多个文件中)作为依赖项的jQuery,我们将为自己创建一个维护问题,如果我们希望在以后更新站点的jQuery版本。我们必须对所有这些文件进行更改以匹配新文件名。

幸运的是,RequireJS使我们能够通过为某些模块定义替代名称来解决这个问题。我们能够创建一个映射到我们的版本化文件名的模块名称,因此我们可以在整个文件中使用该名称来代替直接文件名。这是在RequireJS配置对象中设置的。

让我们启动我们的主应用程序脚本文件(main.js),将此模块名称创建为jQuery的文件名映射:

requirejs.config({paths:{“jquery”:“lib / jquery-1.9.0”}});

我们现在可以在其他模块中的依赖数组中使用模块名称jquery,这将映射到特定的jQuery文件。

RequireJS is used across a number of popular sites, including Instagram, pictured here

RequireJS用于许多热门网站,包括Instagram,如图所示

内容分发网络

许多开发人员更喜欢从Web上的众多全球内容交付网络(CDN)之一引用jQuery的副本。在适当的条件下,这减少了下载文件所花费的时间,并增加了文件可能已经缓存在用户机器上的可能性,如果他们之前访问过从同一CDN加载相同版本的jQuery的另一个网站。

RequireJS允许您仅通过在依赖项数组中使用其URL链接到托管在其他域上的模块。但是我们可以使用之前用于配置jQuery的相同配置设置来简化外部文件依赖项的管理。

我们将使用新的代码片段替换最新的代码片段以引用来自Google的CDN的jQuery - 同时如果外部文件无法加载,它仍然允许它回退到文件的本地版本。我们使用数组链接回退脚本列表:

requirejs.config({paths:{“jquery”:[“https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min”,//如果CDN失败,请从本地加载模块而不是“lib / jquery-1.9.0”]}});

现在我们已经有了我们的文件结构,并且在我们的页面上加载和配置了RequireJS,现在是时候考虑我们应用程序中的文件如何相互依赖。我们已经确定我们的主应用程序脚本依赖于jQuery,以便设置表单提交处理程序和验证该表单的验证脚本。由于验证脚本将构建为jQuery插件,因此它也依赖于jQuery。我们可以用一个表来描述:

我们现在可以在validation-plugin.js文件中编写验证jQuery插件模块的代码,将jQuery指定为唯一的依赖项。模块检查给定字段的值是否为电子邮件地址的典型格式,如果有效则返回true,否则返回false:

define([“jquery”],function($){$ .fn.isValidEmail = function(){var isValid = true,regEx = /\ S+@\S+\.\S+/; this.each(function(){ if(!regEx.test(this.value)){isValid = false;}}); return isValid;};});

我们从调用define方法中省略了可选的模块名称参数,因此模块将使用相对于RequireJS位置的文件名进行注册。它可以通过模块名称lib / validation-plugin在其他依赖项中引用。

RequireJS supports the loading of script dependencies from external URLs, including accessing jQuery directly from Google's hosted libraries site on its CDN

RequireJS支持从外部URL加载脚本依赖项,包括直接从其CDN上的托管库站点访问jQuery

完成代码

现在我们已经建立了依赖关系,是时候完成主应用程序脚本文件中的代码了。我们不打算在这里使用define方法。相反,我们将使用RequireJS的require方法。这两种方法具有相同的模式,但它们的使用方式不同。

前者用于声明模块供以后使用,而后者用于加载依赖项以立即执行,而无需从中创建可重用模块。后一种情况适合我们的主应用程序脚本,该脚本仅执行一次。

这里,在我们的main.js文件中的配置代码下面,我们声明了我们的代码,用于附加到HTML表单的submit事件,使用我们的新插件脚本执行验证,并允许表单在提供的电子邮件地址有效时提交:

require([“jquery”,“lib / validation-plugin”],function($){var $ form = $(“#form”),$ email = $(“#email”); $ form.on(“提交“,function(e){e.preventDefault(); if($ email.isValidEmail()){$ form.get(0).submit();} else {$ email.addClass(”error“)。focus ();}}); $ email.on(“keyup”,function(){$ email.removeClass(“error”);});});

当在浏览器中执行此代码时,将首先加载jQuery库,然后加载我们的验证插件模块。您会记得,当我们定义验证模块时,我们指定它也依赖于jQuery。

RequireJS的一个非常强大的功能是,如果遇到已经被引用的依赖项,它将使用内存中的存储值而不是再次下载它。这使我们能够正确定义依赖关系,而不会影响下载的数据量。

一旦加载了依赖项,就会执行该函数 - 来自作为参数传递的依赖项的任何返回值。因为我们将验证器模块定义为jQuery插件,所以我们没有指定返回值;它将被添加到jQuery $变量中(与其他插件一样)。

RequireJS is based on the Asynchronous Module Definition (AMD) API, described in more detail on its own GitHub project page

RequireJS基于异步模块定义(AMD)API,在其自己的GitHub项目页面上有更详细的描述

走得更远

我们可以扩展我们的代码,以利用RequireJS可以在需要的确切时间点按需加载JavaScript依赖项的事实。而不是在页面加载时加载我们的验证插件(正如我们现在所做的那样),我们只需要在用户提交表单时加载并提供该插件。这样做可以通过减少请求页面时下载的数据量和执行的代码来提高页面加载性能。

RequireJS使我们只需通过调用require方法即可在我们希望下载额外依赖项的位置完成此操作。我们可以重写我们的主应用程序脚本,在页面加载时删除对验证插件的依赖,并将其添加到用户尝试提交表单的位置。

如果用户从未提交表单,则永远不会加载此文件。

require([“jquery”],function($){var $ form = $(“#form”),$ email = $(“#email”); $ form.on(“submit”,function(e){ e.preventDefault(); require([“lib / validation-plugin”],function(){if($ email.isValidEmail()){$ form.get(0).submit();} else {$ email。 addClass(“error”)。focus();}});}); $ email.on(“keyup”,function(){$ email.removeClass(“error”);});});

当用户尝试提交表单时,将加载验证程序插件并尝试验证。如果用户第二次尝试验证,则验证程序插件已加载,因此不会再次下载。

当然,在文件下载之前不能进行表单提交,因此,如果插件脚本是大文件,这可能会影响页面的感知响应性。

如果您愿意,可以通过在用户首先关注表单中文本字段的位置下载验证器插件来抵消这种情况。这应该给浏览器足够的时间来下载插件文件,因此它已准备好用户尝试提交表单的时间点。

RequireJS supports loading of JavaScript files dynamically on demand as your application needs them, reducing the number of HTTP requests on page load

RequireJS支持在应用程序需要时动态加载JavaScript文件,减少页面加载时的HTTP请求数

结论

在本教程中,我将向您介绍如何构建一个简单的页面,该页面使用RequireJS来简化代码文件依赖项的管理,并在需要时启用脚本文件加载的延迟。这种方法不仅可以在代码增长时更轻松地管理代码,还可以通过仅在需要的时刻加载所需的代码来提高Web应用程序的性能。

RequireJS的功能超出了我的覆盖范围。我鼓励您阅读库主页上的文档,以了解如何使用许多配置选项,如何为模块提供替代名称,如何直接从JSONP Web服务加载和存储数据,以及如何加载和管理多个版本的同一模块(在许多其他功能中)。

这种代码依赖管理和脚本文件加载的方法是当今世界上不断增长的JavaScript重型代码库,用于网站和应用程序。了解更多信息并在您自己的网站上采用它以获得收益。快乐的编码!

话: 丹尼斯奥德尔

这篇文章最初出现在网络杂志问题240。

喜欢这个?阅读这些!

任何问题?在评论中提问!



翻译字数超限