Dojo now supports modules written in the Asynchronous Module Definition (AMD) format, which makes code easier to author and debug. In this tutorial, we learn all about this new module format, and explore how to write an application using it.

dojo现在支持异步模式定义的模块,这会让你的代码更有可读性以及可调试性。在本章中,我们会学习该模式,并了解如何在应用中使用它。

This tutorial is a follow-up to the Introduction to AMD, so make sure you understand the basics of AMD first.

本章节是Introduction to AMD,的延续,所以请你确定你已经理解了AMD的一些基础知识。

Throughout this tutorial, we will be referring to a hypothetical application with a filesystem structure that looks like this:

通过本文章,我们将会虚拟一个应用程序,其文件结构如下所示:

 /
index.html
js/
lib/
dojo/
dijit/
dojox/
my/
util/

As you can see, this structure is different from what we discussed in the previous tutorial, so we will explain how to configure the loader to make this work. But first let's revisit require and define with a few more details...

就像你看到的,本结构和我们上面那个例子中的文件结构不一样。所以我们会说明如何配置加载器,以保证代码可以运行。但是,在此之前,我们还是通过几个例子回顾一下require和define函数。

Delving Deeper into require

更深入的了解require函数

The require function accepts the following parameters:

require函数接受下面的参数。

  1. configuration (optional, default=undefined): an object with loader configuration options - this allows you to reconfigure the loader at run-time.

    配置:(可选的,默认值=undefined):加载器配置设置对象-该对象可以允许你在运行时重新配置加载器。

  2. dependencies (optional, default=[]): an array of module identifiers. If specified, these modules will be resolved before your code is evaluated. They will be loaded in the order they are listed and passed as parameters to your callback function, also in order.

    依赖(可选的,默认值=[]):模块标识数组。如果被指定,这些模块在你的代码被执行之前就会被加载。模块会按照其顺序加载,并作为参数按顺序传递给回调函数。

  3. callback: a function containing the code you want to run that depends on the modules in dependencies. You need to wrap your code in a callback function in order to support asynchronous loading and to be able to use non-global references to the modules.

回调函数:该函数是基于在依赖参数中加载的模块而编写的你想运行的代码。为了支持异步加载,并且能够使用非全局命名的模块,你必须把你的代码包在回调函数中。

The configuration parameter can simply be omitted, no empty placeholder value is necessary.

配置参数可以省略,不需要空的占位符。

We'll cover configuring the loader in more detail below; for now here's an example of using the configuration parameter of require:

下面我们将详细介绍加载器配置。下面有一个在require函数中使用配置参数的例子。

 require({
baseUrl: "/js/",
packages: [
{ name: "dojo", location: "//ajax.googleapis.com/ajax/libs/dojo/1.10.4/" },
{ name: "my", location: "my" }
]
}, [ "my/app" ]);

Here, we’ve changed the configuration slightly to point the dojo package to the Google CDN. Cross-domain loading support is implicit in the AMD format.

在这儿,我们稍微改变了dojo包的一些配置,把包指向了google cdn。AMD模式默认是支持跨域的。

Note that not all configuration options can be set at runtime. In particular, async, tlmSiblingOfDojo, and pre-existing has tests cannot be changed once the loader is loaded. Additionally, most configuration data is shallow copied, which means that you couldn’t use this mechanism to, for example, add more keys to a custom configuration object—the object would be overwritten.

需要注意的是,所有的配置都可以在运行时设置。但,async, tlmSiblingOfDojo以及预先存在的has等模块,一旦通过加载器加载后,就不能再修改了。此外,大多数的配置数据都是浅拷贝,这意味着一个配置对象可能会有多个指针引用着该对象,该对象中的数据随时都与可能被覆写。

Delving Deeper into define 深入了解define函数

The define function accepts the following parameters:

define函数包含了下列参数:

  1. moduleId (optional, default=undefined): a module identifier. This parameter is largely a historical artifact of early AMD loaders or to support pre-AMD Dojo, and should not be provided.

    模块ID(可选参数,默认值=undefined):一个模块标识。该参数基本上为了兼容以前的AMD模式二创建的,一般我们不需要提供。

  2. dependencies (optional, default=[]): an array of module identifiers that are dependencies of your module. If specified, these modules will be resolved before your module is evaluated and they will be passed as parameters to your factory function, in order.
    依赖(可选参数,默认值=[]):你的模块需要引用的模块标识集合。在你的模块主代码执行前,这些依赖模块将被加载,并把参数按照依赖模块顺序传递给工厂函数。
  3. factory: the value of your module, or a "factory" function that will return the value

工厂:该函数是你定义模块的主体,或者改工厂函数会作为返回值返回调用者。

It's important to remember that when defining a module, the factory function is only ever invoked once—the returned value is cached by the loader. On a practical level, this means that modules can very easily share objects (similar to static properties in other languages) by loading the same module.

有一点需要注意,当定义一个模块时,工厂函数只会被调用一次-返回值会被加载器缓存。这就意味着,可以通过加载同样模块的方式,共享模块对象(类似于其他开发语言中国的静态属性)。

When defining a module, the value can be given as a plain object:

当定义一个模型,我们可以范围一个普通的对象。

 // in "my/nls/common.js"
define({
greeting: "Hello!",
howAreYou: "How are you?"
});

Keep in mind that if you do define a module without using a factory function, you won’t be able to reference any dependencies, so this type of definition is rare and usually only gets used by i18n bundles or simple configuration objects.

请记住,如果使用工厂模式定义模块,你就不能访问引用任何依赖。所以这种类型的定义不常用,只会在多语言支持的时候会简单配置对象的时候使用。

How does the loader work?

When you call require to load some modules, the loader has to find the code for the module and then pass it as a parameter to your callback function so you can use it.

当你调用require函数加载一些模块的时候,加载器会先找到你调用模块的代码,然后把模块对应的参数传递到回调函数中。

  1. First the loader has to resolve the module identifier you passed. This involves putting together the baseUrl with the module identifier itself, plus taking into account any modifications required by other configuration options, such as map (discussed later in more detail).

    首先,加载器会解析你加载的模块标识。在解析的时候会把配置的baseurl和模块本身的标识结合在一起,同时兼顾其他配置项配置的参数(例如映射参数)。

  2. At this point the loader has a URL for the module and can load the actual file by creating a new script element on the page and setting the src attribute to the module's URL.

    加载器已经有了模块的URL地址,并且可以在页面上添加一个脚本节点,并把模块的URL地址赋值给该脚本节点的src属性。

  3. Once the file is loaded and evaluated, its result is set as the value of the module.

    一旦文件被加载,文件中包含的结果就会被设置成模块的值。

  4. The loader maintains a reference to each module, so the next time the module is requested the loader will return the existing reference.

加载器包含了对每个模块的引用,所以下一步,被加载器加载的模块会返回各自的引用。

When an AMD module is loaded, the code is inserted into a new script element on the page which results in the define function being called. The same process as above happens to load any dependencies passed to define, then the loader's reference to your module is set to the value returned by the factory function you passed to define. (If you passed a value, rather than a function to define, then the loader's reference to your module is set to that value.)

当一个AMD模块被加载后,在调用define函数被调用的页面上,会添加一个新的脚本节点。

Configuring the loader配置加载器

For legacy compatibility reasons, Dojo's loader runs by default in synchronous mode. To put the "A" in "AMD", we need to explicitly configure the loader to run asynchronously. This is done by setting the async configuration property to true:

为了兼容老版本的原因,dojo默认是以同步模式运行的。但在AMD中的A的意思就表明当代的dojoAMD模式都是以异步运行的。在配置中,把async属性设置为true就可以了。

 <script data-dojo-config="async: true" src="js/lib/dojo/dojo.js"></script>

You should get in the habit of enabling this as a standard practice - only disable it when you know you need synchronous behavior. The next thing we need to do is configure the loader with information about where our modules are located:

你应该把该配置作为一种习惯,除非你明确的知道你要同步执行某一个动作。下一步要做的事情就是配置本地的模型路径相关的信息。

 var dojoConfig = {
baseUrl: "/js/",
tlmSiblingOfDojo: false,
packages: [
{ name: "dojo", location: "lib/dojo" },
{ name: "dijit", location: "lib/dijit" },
{ name: "dojox", location: "lib/dojox" },
{ name: "my", location: "my", main: "app" }
]
};

Keep in mind you must set the dojoConfig variable before loading dojo.js. Read the Configuring Dojo tutorial if you haven't already.

需要注意的是,你必修在加载dojo.js后,再设置dojoConfig。

Let's examine the configuration options we're using:

让我们检查一下我们配置的选项:

baseUrl (default = the path of the folder dojo.js was loaded from): defines the base URL for loading packages. For example, if you try to load the module "my/widget/Person", the loader will try to load it from:

baseUrl(默认值是加载的dojo.js所在的目录):定义加载包的基础路径。例如你想加载“my/widget/Person”这个模块,加载器会从下面的路径加载。

 /js/my/widget/Person.js

This allows us to place our files wherever is most convenient in the filesystem (in this case, the "js" folder) and still use only the relevant parts of the path in module ids - we don't need to require(["js/my/widget/Person"]), we can simply require(["my/widget/Person"]) because we have configured the loader to use "/js/" as a base to prepend to all module ids when actually loading the source file.

这样就可以让我们把我们定义的文件放在合适的物理文件目录下,但只需要引用部分路径作为模块的ID标识即可。我们不需要require(["js/my/widget/Person"]),只需要简单的使用require(["my/widget/Person"])就可以了,这是因为我们已经在加载器中配置了baseUrl属性为"/js/",当加载模块时,所有的模块路径都是使用baseUrl+模块标识的方式获取模块源文件。

tlmSiblingOfDojo (default = true): by default, the loader expects to find modules in folders that are siblings of the folder the loader was loaded from (remember, with Dojo the loader is loaded when your script element loads dojo.js). If your file structure is like this:

tlmSiblingOfDojo:默认情况下,加载器可以查找兄弟目录下的所有模块,并加载,例如:

 /
js/
dojo/
dijit/
dojox/
my/
util/

Then you don't need to configure baseUrl or tlmSiblingOfDojo — your top-level modules are siblings of the folder dojo.js was loaded from, so tlmSiblingOfDojo is true.

这样的情况下,你就不需要再配置baseurl和tlmSiblingOfDojo属性了。因为你自定的的模型顶级目录和dojo.js所在的目录为兄弟目录,而模型情况下,tlmSiblingOfDojo的值为true。

packages: an array of package configuration objects. At the most fundamental level, packages are simply collections of modules. dojo, dijit, and dojox are all examples of packages. Unlike a simple collection of modules in a directory, however, packages are imbued with some extra features that significantly enhance module portability and ease-of-use. A portable package is self-contained and also can be installed through tools like cpm. A package configuration allows you to specify:

包:是一组包配置集合。在最基本的层面上,包是一组组模块的集合,例如dojo、dijit、dojox等包。不只是把模块简单的放在一个目录下,包里面还包含了一些其他额外的功能,这可以提高包的可移植性和易用性。包是自包含的,可以通过例如cpm这样的工具进行安装,一个包的配置信息如下:

  • name: the name of the package. This should match the name of the folder that contains the modules.

    name:包的名称。该名字应该和包所在目录的名称一致。

  • location: the location of the package; can either be a path relative to baseUrlor an absolute path. We would like to be able to load modules from the dojo package as "dojo/dom" rather than "lib/dojo/dom" (take another look at the file structure at the beginning of this tutorial), so we specify the location property of the dojo package to be "lib/dojo". This informs the loader that an attempt to load the "dojo/dom" module should load the file "/js/lib/dojo/dom.js" (remember, because of baseUrl "js" will be prepended).

    位置:包的位置,可以是基于baseUrl的相对路径,也可以是绝对路径。我们希望可以通过dojo/dom这样的方式从dojo包中加载模块,而不是通过lib/dojo/dom。所以,我们制定了包的路径为lib/dojo。通过这种模式,当你加载dojo/dom模块时,其实加载时/js/lib/dojo/dom.js文件。

  • main (optional, default = main.js): used to discover the correct module to load if someone tries to require the package itself. For example, if you were to try to require "dojo", the actual file that would be loaded is "/js/dojo/main.js". Since we’ve overridden this property for the "my" package, if someone required "my", they would actually load "/js/my/app.js".

main(可选参数,默认值=main.js):如果有人请求包本身,就指向一个默认的模块文件。例如我们请求dojo,那么该请求指向的实际文件可能是/js/dojo/main.js。例如我们重新了my包的main属性为app,所以在加载是会加载"/js/my/app.js"文件。

  • If we tried to require "util", which is not a defined package, the loader would try to load "/js/util.js". You should always define all of your packages in the loader configuration。

    如果我们请求util,该模块是一个未定义的模块,加载器会尝试加载/js/util.js文件,所以你必须在加载器配置中定义好你需要的所有的包。

Using portable modules 使用轻便的模块

One of the most important features of the new AMD loader is the ability to create fully portable packages. For instance, if you had an application that needed to use modules from two different versions of Dojo, the new loader makes this very easy.

Suppose you have an application built on an older version of Dojo and you want to update to the latest and greatest 1.10 release, but there are some updates to Dojo that render your older code non-functional. You can still update to the current release of Dojo for new code, while using a legacy release of Dojo for you older code. This can be accomplished with the map configuration property:

新的AMD下载机的一个最重要的特性之一就是有能力创建完全轻便的模块包。举个例子,如果你有一个应用必须使用dojo某个模块的不同版本,新的加载器就很容易解决这个问题。

假设你现在有一个应用程序是基于老版本的dojo建设的,现在你想升级到最新版本,也就是1.10版本。但可能有一些更新会让你以前的代码无效了。你依然可以为你新的额代码更新为最新的dojo发布包,同时,为你的旧代码使用dojo之前的版本。这点和通过映射配置完成。

 dojoConfig = {
packages: [
{ name: "dojo16", location: "lib/dojo16" },
{ name: "dijit16", location: "lib/dijit16" },
{ name: "dojox16", location: "lib/dojox16" },
{ name: "dojo", location: "lib/dojo" },
{ name: "dijit", location: "lib/dijit" },
{ name: "dojox", location: "lib/dojox" },
{ name: "myOldApp", location: "myOldApp" },
{ name: "my", location: "my" }
],
map: {
myOldApp: {
dojo: "dojo16",
dijit: "dijit16",
dojox: "dojox16"
}
}
};

AMD高级应用(翻译)的更多相关文章

  1. 【PC桌面软件的末日,手机移动端App称王】写在windows11支持安卓,macOS支持ios,龙芯支持x86和arm指令翻译

    面对这场突如其来的变革,作为软件开发者,应该如何选择自己今后的发展方向?桌面软件开发领域还有前景吗? 起源 自从苹果发布m1处理器,让自家Mac支持IOS移动端app运行之后,彻底打破了移动端app和 ...

  2. 图解server端网络架构

    这篇是计算机类的优质首发推荐>>>><图解server端网络架构> 467张图表讲透构建高可用高性能server实战 写给网络架构师 serverproject师的 ...

  3. GCC(警告.优化以及调试选项)

    GCC(警告.优化以及调试选项) [介绍] gcc and g++分别是gnu的c & c++编译器   gcc/g++在执行编译工作的时候,总共需要4步   1.预处理,生成.i的文件 预处 ...

  4. 深入理解计算机系统 第三章 程序的机器级表示 part1

    如题所示,这一章讲解了程序在机器中是怎样表示的,主要讲汇编语言与机器语言. 学习什么,为什么学,以及学了之后有什么用 我们不用学习如何创建机器级的代码,但是我们要能够阅读和理解机器级的代码. 虽然现代 ...

  5. 构建和管理有效API市场的关键步骤

    API市场关键要点 各个行业的公司正在寻找通过外部API扩展服务来塑造数字业务的方法.然而,要获得API的真正好处,是需要超越基本的API管理,再到创建API市场,这是一种专注于连接生产者和消费者的专 ...

  6. CXL联盟正式成立:成员均是行业巨头

    导读 今天,阿里巴巴.思科.戴尔EMC.Facebook.Google.HPE.华为.Intel.微软(按英文首字母排序)联合宣布,CXL联盟(Compute Express Link Consort ...

  7. 2020年度钻石C++C学习笔记(1)《博学谷》

    1.C语言概述 1.1 什么是C语言 一提到语言这个词语,自然会想到的是像英语.汉语等这样的自然语言,因为它是人和人交换信息不可缺少的工具. 而今天计算机遍布了我们生活的每一个角落,除了人和人的相互交 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...

  9. AMD模块介绍(翻译)

    http://dojotoolkit.org/documentation/tutorials/1.10/modules/index.html Dojo支持以异步模型定义(AMD)方式编写的模块,让会让 ...

随机推荐

  1. Less 语法特性

                                     ——(原创翻译:译者添加部分解释和代码运行结果) ♥在线Less编译器:LESS2CSS <一>综述 Less作为CSS的 ...

  2. 解析C#开发过程常见的编程模式

    单例模式: 在多线程的程序开发过程中经常会遇到单例模式[单件模式],它的特点是不是根据客户程序的调用而生成新的实例,而是控制某个类型的实例数量只有一个.也就是说,单例模式就是保证在整个应用程序的生命周 ...

  3. extjs_button

    在网页中,填写的内容都在form(表单)中显示,要交互就要用到按钮.所以,今天试了一下按钮,但不清楚的是js中定义的按钮能显示在页面,但怎样响应php代码呢?实际效果就是点击按钮后,通过什么方式调出数 ...

  4. EMV文档:接收到的ATR不在EMV规定范围,终端需要的操作

    Required terminal behaviour in the event that a terminal receives characters outside the range allow ...

  5. Windows下的Eclipse启动出现:a java runtime environment(JRE) or java development kit(JDK) must be

    打开eclipse的时候回遇到这种情况 解决方案: 进入eclipse.exe所在的目录,在eclipse.ini文件中加入以下两行: -vm <your path to jdk|jre> ...

  6. TOJ3136

                                                          3136: Ubiquitous Religions 时间限制(普通/Java):2000M ...

  7. YII2的增删改查

    insert into table (field1,field2)values('1','2');delete from table where   condition update  table s ...

  8. 小结MapReduce 程序的流程及设计思路

    简单回顾一下,目前系统是WCF三层C/S插件系统.服务器端是WCF程序寄宿在IIS中,其中我的配置设计是长连接,客户端支持多线程,一个volatile的实例对象.客户端用Winform,其中客户端框架 ...

  9. http://note.youdao.com/yws/public/redirect/share?id=2bc2dc6c7df6013e9f8106c005da999a&type=false

    Welcome to MarkdownPad 2 MarkdownPad is a full-featured Markdown editor for Windows. Built exclusive ...

  10. RMAN备份与恢复之初入茅庐

    理解数据库备份 所谓备份实际上是把数据库复制到转储设备的过程. 从备份方式来看数据库备份分为物理备份和逻辑备份,物理备份是把构成数据库的所有文件拷贝到指定的位置的过程,而逻辑备份只是利用SQL语言从数 ...