这篇文章主要介绍了 require.js 深入了解, require.js 特性介绍, 本文讲解了 require.js 和 CommonJS 的兼容、CDN 回退、循环依赖、BaseUrl、JSONP 等内容, 需要的朋友可以参考下
RequireJS 是一个 JavaScript 模块加载器。它非常适合在浏览器中使用, 它非常适合在浏览器中使用,但它也可以用在其他脚本环境, 就像 Rhino and Node. 使用 RequireJS 加载模块化脚本将提高代码的加载速度和质量。
现在,Require.js 是我最喜欢的 Javascript 编程方式。它可以使代码化整为零,并易于管理。而 Require.js Optimizer 能帮助我们将一个较大的应用分散成多个较小的应用,并通过依赖串联起来,最后在编译打包时合并起来。这些原因促使我们使用 require.js。
那么,让我们来看看 require.js 有什么牛逼的特性吧!
与 CommonJS 兼容
AMD (异步模块定义规范) 出现自 CommonJS 工作组。CommonJS 旨在创造 Javascript 的生态系统。 CommonJS 的一个重要部分是 transport/c, 即 AMD 的前身,而 require.js 则是该规范的一个实现。
CommonJS 模块和 AMD 模块的语法差异,主要由于 AMD 需要支持浏览器的异步特性。而 CommonJS 模块则需要同步进行,例如:
- var someModule = require( "someModule" );
- var anotherModule = require( "anotherModule" );
- exports.asplode = function() {
- someModule.doTehAwesome();
- anotherModule.doMoarAwesome();
- };
AMD 模块是异步加载模块的,故而模块定义需要一个数组作为第一个参数,而模块加载完毕后回调的函数作为第二个参数传入。
- define( [ "someModule"], function( someModule ) {
- return {
- asplode: function() {
- someModule.doTehAwesome();
- // 这将会异步执行
- require( [ "anotherModule" ], function( anotherModule ) {
- anotherModule.doMoarAwesome();
- });
- }
- };
- });
然而,在 require.js 中 AMD 亦能兼容 CommonJS 语法。通过 AMD 的 define 函数包装 CommonJS 模块,你也可以再 AMD 中拥有一个 CommonJS 模块,例如:
- define(function( require, exports, module )
- var someModule = require( "someModule" );
- var anotherModule = require( "anotherModule" );
- someModule.doTehAwesome();
- anotherModule.doMoarAwesome();
- exports.asplode = function() {
- someModule.doTehAwesome();
- anotherModule.doMoarAwesome();
- };
- });
实际上,require.js 通过函数. toString 解释回调函数的模块内容,找到其正确的依赖,将其变成一个通常的 AMD 模块。需要注意,如果你使用这种方式编写模块,可能会发生与其他 AMD 加载器不兼容的情况,因为这违背了 AMD 规范,但它能很好的理解这种格式的写法。
这里发生了什么,require.js 实际上做了 function.toString 的回调函数解析模块的内容,找到正确的依赖,就像它,如果它是一个正常的 AMD 模块。重要的是要注意,如果您选择这样写模块,他们将最有可能不兼容与其他 AMD 模块装载机,因为这违背了 AMD 规范,但它是很好的了解这个格式存在!
CDN 回退
另一个隐藏的 require.js 瑰宝是,其支持当 CDN 加载不正确时,回退加载本地相应的库。我们可以通过 require.config 达到这个目的:
- requirejs.config({
- paths: {
- jquery: [
- '//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js',
- 'lib/jquery'
- ]
- }
- });
没有依赖?对象字面量?没问题!
当你写一个没有任何依赖的模块,并且只是返回一个对象包含一些功能函数,那么我们可以使用一种简单的语法:
- define({
- forceChoke: function() {
- },
- forceLighting: function() {
- },
- forceRun: function() {
- }
- });
很简单,也很有用,如果该模块仅仅是功能的集合,或者只是一个数据包。
循环依赖
在一些情况中,我们可能需要模块 moduleA 和 moduleA 中的函数需要依赖一些应用。这就是循环依赖。
- // js/app/moduleA.js
- define( [ "require", "app/app"],
- function( require, app ) {
- return {
- foo: function( title ) {
- var app = require( "app/app" );
- return app.something();
- }
- }
- }
- );
得到模块的地址
如果你需要得到模块的地址,你可以这么做……
- var path = require.toUrl("./style.CSS");
BaseUrl
通常,在进行的单元测试时,你的源代码可能放在类似 src 的文件夹里,同时,可能你的测试放在类似 tests 的文件夹里。这可能比较难让测试配置正确。
比如我们在 tests 文件夹有一个 index.html 文件,并需要本地加载 tests/spec/*.js。并假设,所有源代码在为 src/js/*.js,并有一个 main.js 在该文件夹。
index.html 中,不在加载 require.js 时设置 data-main。
- <script src="src/js/vendor/require.js"></script>
- <script>
- require( [ "../src/js/main.js" ], function() {
- require.config({
- baseUrl: "../src/js/"
- });
- require([
- "./spec/test.spec.js",
- "./spec/moar.spec.js"
- ], function() {
- // start your test framework
- });
- });
- </script>
你可以发现 main.js 被加载。然而由于没有设置 data-main,所欲我们需要制定一个 baseUrl。而当使用 data-main 时,baseUrl 会根据其设定的文件来自动设置。
在这里,你可以看到 main.js 被载入。然而,由于它没有加载数据主要脚本标记,那么您必须指定一个 base 即可。当数据主要是用于 baseURL 时从主文件中的位置推断。通过自定义 baseUrl 我们可以很容易将测试代码和应用代码分开存放。
JSONP
我们可以这样处理 JSONP 终端:
- require( [
- "http://someapi.com/foo?callback=define"
- ], function (data) {
- console.log(data);
- });
对于非 AMD 库,使用 shim 来解决
在很多请款下,我们需要使用非 AMD 库。例如 Backbone 和 Underscore 并未适应 AMD 规范。而 jQuery 实际上只是将自己定义成一个名为 jQuery 全局变量,所以对于 jQuery 什么都不用做。
幸运的是,我们可以使用 shim 配置来解决这一问题。
- require.config({
- paths: {
- "backbone": "vendor/backbone",
- "underscore": "vendor/underscore"
- },
- shim: {
- "backbone": {
- deps: [ "underscore" ],
- exports: "Backbone"
- },
- "underscore": {
- exports: "_"
- }
- }
- });
来源: