使用AMD模块时,在define()内部使用require()什么情况下是可以的(或者为什么可以)?

19

对于 AMD 模块(例如 RequireJs 或 curl.js),我的理解是:

require() 用于异步加载不同的模块,加载完成后执行回调函数。

要定义一个模块,您需要使用 define() 分离脚本。

但是我看到一些模块在其函数定义内部使用了 require(),例如:

define([a, b, c], function(i, ii, iii){ 
    require([d, e, f], function(d, e, f) {
        // do some stuff with these require()'d dependancies
    })
    /* rest of the code for this module */ 
}) 

但我觉得这很令人困惑,因为我原本认为如果一个模块有依赖关系,那么它们应该通过主要的define([dependancies], fnDefinition)函数传递,而不是像上面的示例一样在其内部通过require()传递。

这背后是否有理由呢?

1个回答

28

使用require()在模块中有几个原因。

但是首先,请确保请求正确的require变量的引用。在你的示例中,对require的引用是全局的。你需要一个引用到在你的模块上下文范围内的require(有时称为“本地 require”)。这很容易实现:

define(["a", "b", "c", "require"], function(i, ii, iii, require){ 
    require(["d", "e", "f"], function(moduleD, moduleE, moduleF) {
        // do some stuff with these require()'d dependencies
    })
    /* rest of the code for this module */ 
}); 
这很重要的主要原因是确保相对模块 ID(例如"./peerModule"或"../unclePath/cousinModule")能够正确解析。(这也是为什么curl.js默认情况下没有全局require的原因之一。)
使用本地require的原因:
  1. 由于运行时条件,您不知道哪些模块在构建时(或加载时)需要
  2. 您明确希望推迟加载某些模块,直到它们被需要
  3. 您想根据功能检测结果加载变体模块(尽管像dojo的“ has!”插件可能是更好的解决方案(对不起,我找不到链接))
最后,AMD定义了第二种使用require的方法,以便与使用CommonJS Modules/1.1编写并随后包装在define中的模块兼容。 这看起来像这样:
define(function(require, exports, module){ 
    var a = require("pkgZ/moduleA"), // dependency
        b = require("pkgZ/moduleB"); // dependency
    /* rest of the code for this module */ 
}); 

服务器端JavaScript开发人员可能会觉得这种格式很吸引人。:)

一些AMD加载器(例如RequireJS 0.2+、dojo 1.7+、bdLoad和curl.js 0.6+)将检测到这种混合的AMD/CJSM1.1格式,并通过扫描模块中的require调用来查找依赖项。


我能找到的最好的 has.js 链接是:http://mail.dojotoolkit.org/pipermail/dojo-contributors/2011-January/023462.html 它并没有解释插件,只是提到了它。 - unscriptable
如果有人有足够的积分来创建一个curljs标签,我会很感激!:) - unscriptable
所以,如果我有一个需要某些功能但并非所有浏览器都支持的模块,我可以将其定义为普通模块,然后在内部进行条件检查,然后require()相关的模块来填充缺失的功能,对吗?而且我认为在“构建时”,我仍然可以使用我的构建脚本来缩小该模块,这样就不像我是异步加载未被缩小的模块脚本。 - Integralist
没错,这就是 has! 插件的目的。它的意图是建立一个 UA 字符串到特性配置文件的映射表。您的服务器可以从预编译的连接文件列表中选择一个定制调整的文件,适用于当前浏览器的 UA 字符串 - 或者它可以即时构建一个(并希望将其缓存以备后用)。*应该指出,并非所有人都“赞成”重新引入 UA 嗅探技术! - unscriptable
这是否适用于在 require.config() 块之后指定的第一个入口点 "require"?我已将 enforceDefine 设置为 true,这将 config 块放置在 define() 中,然后在 config 之后使用全局 "require" 调用入口点。 - wayofthefuture

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