浏览器内的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的方法,它完全不会污染全局名称空间,但是仍然允许我加载和使用库(就像节点的require一样)。
2020年更新: 模块现已成为ES6中的标准组件,并且自2020年中期开始,大多数浏览器都原生支持这些模块。模块支持同步和异步(使用Promise)加载。我当前的建议是,大多数新项目应使用ES6模块,并使用转译器回退到旧版浏览器的单个JS文件。
作为一般原则,今天的带宽通常也比我最初提出这个问题时要宽得多。因此,在实践中,您可能会合理地选择始终将转译器与ES6模块一起使用,并将精力集中在代码效率而不是网络上。
以前的编辑(或者,如果您不喜欢ES6模块):自编写此文档以来,我已经广泛使用RequireJS(现在它的文档更加清晰)。在我看来,RequireJS确实是正确的选择。我想澄清一下该系统如何为像我一样困惑的人们工作:
您可以require
在日常开发中使用。模块可以是函数(通常是对象或函数)返回的任何东西,范围可以作为参数。您还可以将项目编译为单个文件以进行部署r.js
(实际上,尽管require
可以并行加载脚本,但这样做几乎总是更快)。
RequireJS和节点样式的require之间的主要区别在于,例如browserify(tjameson建议一个很酷的项目)使用的是模块的设计和需求方式:
- RequireJS使用AMD(异步模块定义)。在AMD中,
require
获取要加载的模块(javascript文件)列表和回调函数。加载每个模块后,它将使用每个模块作为回调的参数来调用回调。因此,它确实是异步的,因此非常适合Web。 - 节点使用CommonJS。在CommonJS中,
require
是一个阻塞调用,它将加载模块并将其作为对象返回。这对于Node来说效果很好,因为文件是从文件系统中读取的,速度足够快,但在Web上效果不佳,因为同步加载文件可能需要更长的时间。
实际上,许多开发人员在使用AMD之前就已经使用过Node(因此也使用了CommonJS)。此外,许多库/模块是为CommonJS(通过向exports
对象添加内容)而不是为AMD(通过从define
函数返回模块)而编写的。因此,许多由Node.com转变为Web的开发人员都希望在Web上使用CommonJS库。这是可能的,因为<script>
标签的加载受到阻碍。诸如browserify之类的解决方案采用CommonJS(Node)模块并将其包装起来,以便可以将它们包含在脚本标签中。
因此,如果您正在开发自己的Web多文件项目,强烈建议使用RequireJS,因为它确实是Web的模块系统(尽管公平地公开,我发现AMD比CommonJS自然得多)。最近,区别变得不那么重要了,因为RequireJS现在允许您实质上使用CommonJS语法。此外,RequireJS可用于在Node中加载AMD模块(尽管我更喜欢node-amd-loader)。