【发布时间】:2011-10-21 17:51:21
【问题描述】:
是否有任何浏览器内 javascript 库提供与 Node 的 require 相同的灵活性/模块化/易用性?
提供更多细节:require 之所以这么好,是因为它:
- 允许从其他位置动态加载代码(在我看来,这在风格上比在 HTML 中链接所有代码更好)
- 它为构建模块提供了一致的界面
- 模块很容易依赖于其他模块(例如,我可以编写一个需要 jQuery 的 API,这样我就可以使用
jQuery.ajax() - 加载的 javascript 是作用域,这意味着我可以使用
var dsp = require("dsp.js");加载并且我将能够访问dsp.FFT,这不会干扰我的本地var FFT
我还没有找到一个可以有效地做到这一点的库。我倾向于使用的解决方法是:
-
coffeescript-concat -- 需要其他 js 很容易,但你必须编译它,这意味着它不适合快速开发(例如在测试中构建 API)
-
RequireJS -- 它很流行,简单明了,并且解决了 1-3,但缺乏范围界定是一个真正的交易破坏者(我相信head.js 是相似的,因为它缺乏范围界定,虽然我从来没有任何使用它的场合。类似地,LABjs 可以加载,
.wait()确实缓解了依赖问题,但它仍然不做作用域)
据我所知,似乎有很多动态和/或异步加载 javascript 的解决方案,但它们往往具有与仅从 HTML 加载 js 相同的范围问题。最重要的是,我想要一种加载 javascript 的方法,它根本不会污染全局命名空间,但仍然允许我加载和使用库(就像 node 的 require 一样)。
2020 年更新:Modules 现在是 ES6 的标准配置,截至 2020 年中期,most browsers 原生支持。模块支持同步和异步(使用 Promise)加载。我目前的建议是大多数新项目应该使用 ES6 模块,并使用转译器为旧版浏览器回退到单个 JS 文件。
作为一般原则,今天的带宽通常也比我最初提出这个问题时宽得多。因此,在实践中,您可能会合理地选择始终使用带有 ES6 模块的转译器,并将精力集中在代码效率而不是网络上。
以前的编辑(或者如果你不喜欢 ES6 模块): 自从写这篇文章以来,我已经广泛使用了RequireJS(现在有更清晰的文档)。在我看来,RequireJS 确实是正确的选择。我想澄清一下这个系统是如何为像我一样困惑的人工作的:
您可以在日常开发中使用require。模块可以是函数返回的任何东西(通常是对象或函数),并且作用域为参数。您还可以使用r.js 将您的项目编译为单个文件进行部署(实际上这几乎总是更快,即使require 可以并行加载脚本)。
RequireJS 和 node-style require 之间的主要区别,比如 browserify(tjameson 推荐的一个很酷的项目)使用的模块是设计和需要的方式:
- RequireJS 使用 AMD(异步模块定义)。在 AMD 中,
require采用要加载的模块列表(javascript 文件)和回调函数。当它加载了每个模块时,它会调用回调,并将每个模块作为回调的参数。因此它是真正异步的,因此非常适合网络。 - 节点使用 CommonJS。在 CommonJS 中,
require是一个阻塞调用,它加载一个模块并将其作为对象返回。这适用于 Node,因为文件是从文件系统读取的,速度足够快,但在 Web 上效果不佳,因为同步加载文件可能需要更长的时间。
实际上,许多开发人员在看到 AMD 之前就使用过 Node(因此也使用过 CommonJS)。此外,许多库/模块是为 CommonJS 编写的(通过向 exports 对象添加内容)而不是为 AMD(通过从 define 函数返回模块)。因此,许多从 Node 转向 Web 的开发人员都希望在 Web 上使用 CommonJS 库。这是可能的,因为从 <script> 标签加载是阻塞的。像 browserify 这样的解决方案采用 CommonJS (Node) 模块并将它们包装起来,以便您可以将它们包含在脚本标签中。
因此,如果您正在为 web 开发自己的多文件项目,我强烈推荐 RequireJS,因为它确实是 web 的模块系统(尽管公平地披露,我发现 AMD 比 CommonJS 更自然)。最近,这种区别变得不那么重要了,因为 RequireJS 现在允许您基本上使用 CommonJS 语法。此外,RequireJS 可用于在 Node 中加载 AMD 模块(尽管我更喜欢 node-amd-loader)。
【问题讨论】:
-
注意 RequireJS 实际上支持模块化并且可以作用域。自从询问以来,我已经更广泛地使用了它。在我看来,它功能丰富,但需要大量阅读文档才能有效使用,并且它需要某种形式的一流同步加载才能完美。
-
异步的区别有意义吗?每当我需要代码时,我基本上无法继续,因为它定义了功能,所以我需要做任何事情......
-
这个问题的答案应该拿出来作为实际答案输入。见Can I answer my own question?
标签: javascript load require scoping