<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>绿色记忆 &#187; RequireJS</title>
	<atom:link href="https://blog.gmem.cc/tag/requirejs/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Mon, 06 Apr 2026 12:46:48 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.14</generator>
	<item>
		<title>RequireJS学习笔记</title>
		<link>https://blog.gmem.cc/requirejs-study-note</link>
		<comments>https://blog.gmem.cc/requirejs-study-note#comments</comments>
		<pubDate>Wed, 24 Feb 2016 01:28:12 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[RequireJS]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">https://blog.gmem.cc/?p=11090</guid>
		<description><![CDATA[<p>基础知识 JS模块系统 所谓模块化，是指应用程序由一组高度解耦的、存放在不同模块中的独特功能构成。 开源框架和ES6引入了多个JavaScript模块化系统： AMD（Asynchronous Module Definition，异步模块定义），RequireJS使用的模块化系统，浏览器优先 CommonJS，Node.js使用的模块化系统，主要用于服务器端JS开发的模块化支持，同步化加载 ES6模块化系统，语言级别的支持 模块加载器 模块系统仅仅是一套规范，浏览器并不理解这些规范。要加载模块，需要模块加载器的配合： RequireJS，理解AMD规范 SystemJS，支持多种模块系统，包括AMD, CommonJS, ES6 es6-module-loader：一个支持ES6模块的垫片库 Browserify，让浏览器可以使用CommonJS模块系统 RequireJS简介 RequireJS是一个JavaScript文件和模块加载器，主要用于浏览器中，也支持Node.js之类的后端JavaScript运行环境。使用RequireJS有利于提高加载速度（异步）、帮助提高代码质量（模块化）。 RequireJS是AMD规范的实现，比起同步化的CommonJS规范，AMD更加适用于浏览器环境。 RequireJS支持绝大部分浏览器，包括IE 6.0。 <a class="read-more" href="https://blog.gmem.cc/requirejs-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/requirejs-study-note">RequireJS学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">基础知识</span></div>
<div class="blog_h2"><span class="graybg">JS模块系统</span></div>
<p>所谓模块化，是指应用程序由一组高度解耦的、存放在不同模块中的独特功能构成。</p>
<p>开源框架和ES6引入了多个JavaScript模块化系统：</p>
<ol>
<li>AMD（Asynchronous Module Definition，异步模块定义），RequireJS使用的模块化系统，浏览器优先</li>
<li><a href="/intro-to-commonjs-spec">CommonJS</a>，Node.js使用的模块化系统，主要用于服务器端JS开发的模块化支持，同步化加载</li>
<li>ES6模块化系统，语言级别的支持</li>
</ol>
<div class="blog_h2"><span class="graybg">模块加载器</span></div>
<p>模块系统仅仅是一套规范，浏览器并不理解这些规范。要加载模块，需要模块加载器的配合：</p>
<ol>
<li>RequireJS，理解AMD规范</li>
<li>SystemJS，支持多种模块系统，包括AMD, CommonJS, ES6</li>
<li>es6-module-loader：一个支持ES6模块的垫片库</li>
<li>Browserify，让浏览器可以使用CommonJS模块系统</li>
</ol>
<div class="blog_h2"><span class="graybg">RequireJS简介</span></div>
<p>RequireJS是一个JavaScript文件和模块加载器，主要用于浏览器中，也支持Node.js之类的后端JavaScript运行环境。使用RequireJS有利于提高加载速度（异步）、帮助提高代码质量（模块化）。</p>
<p>RequireJS是AMD规范的实现，比起同步化的CommonJS规范，AMD更加适用于浏览器环境。</p>
<p>RequireJS支持绝大部分浏览器，包括IE 6.0。</p>
<p>可以到<a href="http://requirejs.org/docs/download.html">http://requirejs.org/docs/download.html</a>下载RequireJS。</p>
<div class="blog_h2"><span class="graybg">HelloWorld</span></div>
<p>为了有效的利用RequireJS优化工具，你应当把所有内联的脚本移出HTML文件。并且，在HTML中仅仅引用require.js：</p>
<pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;title&gt;RequireJS Study&lt;/title&gt;
&lt;!-- data-main提示RequireJS，在其自身被加载后，立即加载js/index.js文件 --&gt;
&lt;script type="text/javascript" src="requirejs/require.js" data-main="js/index"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>如果要<span style="background-color: #c0c0c0;">避免</span>RequireJS的加载动作<span style="background-color: #c0c0c0;">阻塞UI渲染</span>，可以把<pre class="crayon-plain-tag">&lt;script&gt;</pre> 标签放到<pre class="crayon-plain-tag">&lt;body&gt;</pre> 元素的后面。</p>
<p>上述的index.js，是应用程序的<span style="background-color: #c0c0c0;">主脚本文件</span>。 在此文件中，你可以使用RequireJS的API来加载任何其它你所需要的JavaScript文件：</p>
<pre class="crayon-plain-tag">console.log( 'loading index.js' );
// 加载目标JavaScript文件
// 使用模块标识符（module IDs）代替URL。模块标识符不需要加.js后缀，因为默认情况下RequireJS把所有文件都当做JS看待，此后缀会自动添加
requirejs( [ "utils/string-utils" ], function( util ) {
    /**
     * 此回调在js/utils/string-utils.js加载完毕后执行&lt;br&gt;
     * 如果string-utils.js中包含对define()的调用，那么此回调直到string-utils.js的依赖也被加载后，才执行
     */
    console.log( 'utils/string-utils.js loaded' );
} );</pre><br />
<pre class="crayon-plain-tag">console.log( 'loading utils/string-utils.js' );
// 定义此文件的依赖
define( [ 'utils/utils' ], function() {
    console.log( 'utils/utils.js loaded' );
} );</pre><br />
<pre class="crayon-plain-tag">console.log( 'loading utils/utils.js' );</pre>
<p>打开浏览器访问index.html，控制台输出如下：</p>
<pre class="crayon-plain-tag">loading index.js
loading utils/string-utils.js
loading utils/utils.js
utils/utils.js loaded
utils/string-utils.js loaded</pre>
<p>可以很清晰的看出RequireJS加载脚本的顺序。</p>
<div class="blog_h1"><span class="graybg">用法</span></div>
<div class="blog_h2"><span class="graybg">加载JS文件</span></div>
<p>与传统的<pre class="crayon-plain-tag">&lt;script&gt;</pre> 标签不同，RequireJS采用了不同的脚本加载机制。</p>
<p>RequireJS总是基于<pre class="crayon-plain-tag">baseUrl</pre> 的相对路径加载新的JS，<span style="background-color: #c0c0c0;">baseUrl通常是data-main属性指定的脚本所在目录</span> 。data-main属性指定了<span style="background-color: #c0c0c0;">脚本加载的起始点</span>。调用下面的函数可以手工设置baseUrl：</p>
<pre class="crayon-plain-tag">require.config( {
    baseUrl : "/another/path"
} );</pre>
<p>如果既没有调用上述函数，也没有设置data-main属性，那么baseUrl和引用require.js的HTML的URL所在目录一致。</p>
<p>RequireJS<span style="background-color: #c0c0c0;">默认假设所有依赖均为JavaScript脚本</span>，因此将模块标识符转换为URL时，它会自动添加.js后缀。</p>
<p>如果<span style="background-color: #c0c0c0;">模块标识符具有.js后缀、以/开头、或者包含http/https，则直接当做URL处理</span>，不使用baseUrl + ModuleID + .js方式组装出URL。</p>
<p>RequireJS允许从不同位置加载模块：</p>
<pre class="crayon-plain-tag">requirejs.config( {
    // 默认的，模块从js/lib目录下加载
    baseUrl : 'js/lib',
    paths : {
        // 对于app开头的模块标识符，则从js/app目录加载
        app : '../app'
    }
} );</pre>
<div class="blog_h2"><span class="graybg">data-main入口点</span></div>
<p>data-main属性用来指定<span style="background-color: #c0c0c0;">初始执行</span>的模块标识符，此模块类似于传统编程语言的main函数，你可以在其中对RequireJS进行配置并加载第一个业务模块。</p>
<p>你不<span style="background-color: #c0c0c0;">能假设此模块先于DOM中后续声明的JS加载和执行</span>，原因是RequireJS默认为<pre class="crayon-plain-tag">&lt;script&gt;</pre> 标签添加了<pre class="crayon-plain-tag">async</pre> 属性。在data-main后声明其它脚本（额外的入口点）标签违背了其用意，data-main只适合<span style="background-color: #c0c0c0;">单个入口点</span>的情形。</p>
<div class="blog_h2"><span class="graybg">定义模块</span></div>
<p><span style="background-color: #c0c0c0;">模块通常和JS文件一一对应</span>，但是模块可以声明依赖关系、并且避免全局NS污染。 通过依赖关系树，RequireJS允许<span style="background-color: #c0c0c0;">并发的加载多个模块</span>，提高速度。</p>
<div class="blog_h3"><span class="graybg">简单的模块</span></div>
<p>包含两个变量声明的模块：</p>
<pre class="crayon-plain-tag">define( {
    name : "Alex",
    age : 30
} );</pre>
<p>如果需要进行前置的初始化动作，可以使用函数式定义：</p>
<pre class="crayon-plain-tag">define( function() {
    //执行前置工作
    return {
        name : "Alex",
        age: 30
    }
} );</pre>
<p>注意：</p>
<ol>
<li><span style="background-color: #c0c0c0;">模块初始化函数的返回值不一定是对象</span>，任何合法的JavaScript函数返回值都是可以的，例如函数</li>
<li>遵循AMD规范的模块，其代码必须完全放置在模块初始化函数中，以避免全局NS的污染</li>
</ol>
<div class="blog_h3"><span class="graybg">包含依赖的模块</span></div>
<p>可以在定义模块时声明其依赖，依赖加载完毕之前，模块初始化函数不会被调用：</p>
<pre class="crayon-plain-tag">define( [ './room', './dining-table' ], function() {
    return {
        name : "Alex",
        age : 30
    }
} );</pre>
<div class="blog_h3"><span class="graybg">使用依赖</span></div>
<p>依赖模块可以直接作为入参，注入到当前模块的初始化函数的入参中：</p>
<pre class="crayon-plain-tag">// app/room.js
define( {
    no : '1103'
} );
// app/person.js
define( [ './room', './dining-table' ], function( room ) {
    return {
        name : "Alex",
        age : 30,
        roomNo : room.no,
    }
} );</pre>
<p>注意，入参注入的顺序，必须和模块依赖声明顺序一致。 </p>
<div class="blog_h3"><span class="graybg">定义命名模块</span></div>
<p>你可以显式的命名模块：</p>
<pre class="crayon-plain-tag">define( 'app/person', [ './room', './dining-table' ], function() {
    return {
        name : "Alex",
        age : 30
    }
} );</pre>
<p>通常不建议这样做，模块名称应当由优化工具根据JS文件名自动生成，这样可以增强可移植性并且利于多模块的打包。</p>
<div class="blog_h3"><span class="graybg">JSONP服务依赖</span></div>
<p>可以将JSONP服务作为依赖声明，此时必须将JSONP的GET参数callback的值设置为define：</p>
<pre class="crayon-plain-tag">require( [ "http://gmem.cc/api/data.json?callback=define" ], function( data ) {
    // data就是JSONP返回的响应内容
} );</pre>
<p>JSONP服务的返回值<span style="background-color: #c0c0c0;">必须是JSON对象</span>，数组、数字、字符串等不支持。</p>
<div class="blog_h3"><span class="graybg">取消模块定义</span></div>
<p>函数<pre class="crayon-plain-tag">requirejs.undef()</pre> 可以让RequireJS忘记已经定义的某个模块。该函数使用的前提是，目标模块<span style="background-color: #c0c0c0;">尚未被引用</span>。 </p>
<div class="blog_h2"><span class="graybg">配置</span></div>
<p>有几种方式来指定RequireJS的配置项。首先，你可以在顶级HTML或者JS中调用<pre class="crayon-plain-tag">config()</pre> 函数：</p>
<pre class="crayon-plain-tag">&lt;script src="scripts/require.js"&gt;&lt;/script&gt;
&lt;script&gt;
  require.config({
  });
&lt;/script&gt;</pre>
<p>在data-main入口点调用此函数也是可以的，但是要注意data-main脚本的异步加载特性。</p>
<p>另外，你可以在RequireJS加载前，在全局变量require中存放配置信息：</p>
<pre class="crayon-plain-tag">&lt;script&gt;
    var require = {
    };
&lt;/script&gt;
&lt;script src="scripts/require.js"&gt;&lt;/script&gt;</pre>
<div class="blog_h3"><span class="graybg">配置项列表 </span></div>
<table class=" full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 120px; text-align: center;">配置项</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>baseUrl</td>
<td>查找所有模块（除非匹配paths）对应文件时，使用的基础URL前缀。支持跨域加载</td>
</tr>
<tr>
<td>paths</td>
<td>用于映射不存放在baseUrl下面的模块，可以指定模块的多个备选加载位置：<br />
<pre class="crayon-plain-tag">requirejs.config(
    {
        enforceDefine: true,
        paths: {
            jquery: [
                //优先从CND加载
                'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
                //如果失败，从本地目录加载
                'lib/jquery'
            ]
        }
    }
);</pre>
</td>
</tr>
<tr>
<td>shim</td>
<td>为那些非标准模块（没有使用define定义，且符合AMD规范）执行依赖和导出配置</td>
</tr>
<tr>
<td>map</td>
<td>执行模块标识符映射，用于从不同位置加载不同模块的依赖项，对于使用多个库版本的大型项目有用：<br />
<pre class="crayon-plain-tag">requirejs.config( {
    map : {
        // 支持通配符，匹配所有没有详细规定的模块
        '*' : {
            'jquery' : 'jquery-2.2.2'
        },
        // 对于新模块，加载1.7版本的jQuery依赖
        'app/newmodule' : {
            'jquery' : 'jquery-1.7'
        },
        // 对于旧模块，加载1.0版本的jQuery依赖
        'app/oldmodule' : {
            'jquery' : 'jquery-1.0'
        }
    }
} );</pre>
</td>
</tr>
<tr>
<td>config</td>
<td>用于向某个模块传递（应用级别的）配置信息：<br />
<pre class="crayon-plain-tag">requirejs.config( {
    config : {
        'bar' : {
            size : 1
        }
    }
} );
// bar.js
define( function( require, exports, module ) {
    var size = module.config().size;
} );</pre></p>
<p>注意，当向一个包传递配置信息时，应该把包的主模块（Main module）作为键，而不是包ID：</p>
<p><pre class="crayon-plain-tag">requirejs.config( {
    config : {
        'pkg/index' : { // 向包传递配置时，这里必须使用包的主模块
            apiKey : 'XJKDLNS'
        }
    },
    packages : [ {
        // 声明一个pkg包，主模块为index
        name : 'pkg',
        main : 'index'
    } ]
} );</pre>
</td>
</tr>
<tr>
<td>packages</td>
<td>用于从CommonJS包中加载模块</td>
</tr>
<tr>
<td>nodeIdCompat</td>
<td> Node.js将app.js和app看做同一个模块标识符，在RequireJS中默认不是。将此配置项设置为true，可以和Node.js兼容</td>
</tr>
<tr>
<td>waitSeconds</td>
<td> 加载一个脚本的超时秒数，默认7。设置为0则永不超时</td>
</tr>
<tr>
<td>context</td>
<td>用于在同一个页面加载一个模块的多个版本 </td>
</tr>
<tr>
<td>deps</td>
<td>声明一个依赖的数组，这些依赖在require被定义后，立即异步的加载 </td>
</tr>
<tr>
<td>callback</td>
<td>当deps加载完毕后执行的回调函数</td>
</tr>
<tr>
<td>enforceDefine</td>
<td>如果设置为true，RequireJS发现加载的JS没有调用define()且不具有可供检查的shim导出字符串值时，会抛出异常</td>
</tr>
<tr>
<td>xhtml</td>
<td>如果设置为true，RequireJS使用document.createElementNS()来创建script元素</td>
</tr>
<tr>
<td>urlArgs</td>
<td>RequireJS获取资源时，使用的额外URL参数，形式：<pre class="crayon-plain-tag">pname1=pval1&amp;pname2=pval2</pre>  <br />从2.2.0版本开始，此参数可以是一个函数：<br />
<pre class="crayon-plain-tag">// id模块标识符，url依赖的URL
function(id,url){};</pre>
</td>
</tr>
<tr>
<td>scriptType</td>
<td>脚本的MIME类型，默认text/javascript</td>
</tr>
<tr>
<td>skipDataMain</td>
<td>从2.1.9开始，设置为true，则不会尝试去寻找data-main属性。当RequireJS被嵌入到一个工具库中时有用 </td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">shim配置：和非AMD兼容的脚本一起工作</span></div>
<p>shim用于描述非标准模块的特征，你可以声明非标准模块的依赖项和“导出符号”。导出符号（exports）指出非标准模块中的哪一个全局变量<span style="background-color: #c0c0c0;">代表此模块</span>：</p>
<pre class="crayon-plain-tag">console.log( 'Module: Utils loaded.' );</pre><br />
<pre class="crayon-plain-tag">console.log( 'Module: StringUtils loaded.' );
var StringUtils = {
    /**
     *
     * @param {String} str
     * @param {String} search
     */
    indexOf: function ( str, search ) {
        return str ? str.indexOf( search ) : -1;
    }
}
var StringUtilsBase = {};</pre><br />
<pre class="crayon-plain-tag"> require.config(
    {
        baseUrl: 'js',
        shim: {
            'utils/StringUtils': {
                // 确保Utils.js先于StringUtils.js加载，尽管两者都不遵循AMD规范
                deps: [ 'utils/Utils' ],
                // 在StringUtils.js中定义的全局变量StringUtils代表模块
                exports: 'StringUtils'
            }
        }
    }
);
require( [ 'utils/StringUtils' ], function ( SU ) { //SU == StringUtils，由于exports配置
    console.log( StringUtils.indexOf );
    console.log( SU.indexOf );
} );</pre>
<p>上述代码运行结果如下：</p>
<pre class="crayon-plain-tag">Module: Utils loaded.
Module: StringUtils loaded.
function ( str, search ) { return str ? str.indexOf( search ) : -1; }
function ( str, search ) { return str ? str.indexOf( search ) : -1; }</pre>
<p>你还可以指定init配置项，这是一个函数，其返回值代表模块：</p>
<pre class="crayon-plain-tag">require.config(
    {
        baseUrl: 'js',
        shim: {
            'utils/StringUtils': {
                init: function () {
                    return {
                        StringUtils: StringUtils,
                        StringUtilsBase: StringUtilsBase
                    }
                }
            }
        }
    }
);</pre>
<p>init和exports配置项冲突，不得联用。 </p>
<div class="blog_h3"><span class="graybg">package配置：从CommonJS包中加载模块</span></div>
<p>RequireJS支持CommonJS的Package规范，可以从中加载模块。每个CommonJS包可以分配一个模块名称/前缀，对于每个包，其package配置可以指定以下属性：</p>
<ol>
<li>name：包的名称，用于模块名称/前缀映射</li>
<li>location：包的位置，此URL相对于baseUrl，除非包含http/https或者以/开始</li>
<li>main：包中的一个模块的名称，当某个脚本对包名进行require时，会自动require此“主模块”，默认值为main</li>
</ol>
<p>package配置的示例：</p>
<pre class="crayon-plain-tag">require.config(
    {
        //这里声明了两个保
        packages: [
            "cart",
            {
                name: "store",
                main: "store" //指定主模块
            }
        ]
    }
);
require( ['cart'],function(cart){} ); //cart/main.js会被加载</pre>
<div class="blog_h2"><span class="graybg">错误处理</span></div>
<p>RequireJS遇到的错误一般是404，或者通信超时，RequireJ提供了几种错误处理方式：</p>
<ol>
<li>在调用require时指定回调，举例：<br />
<pre class="crayon-plain-tag">require( [ 'jquery' ], function ( $ ) {
}, function ( err ) { //第二个参数是错误处理回调
    var failedId = err.requireModules &amp;&amp; err.requireModules[ 0 ];//requireModules为失败的模块的列表
    if ( failedId === 'jquery' ) {
        // 取消jQuery的定义，重新配置和加载
        requirejs.undef( failedId );
        requirejs.config(
            {
                paths: {
                    jquery: 'local/jquery'
                }
            }
        );
        require( [ 'jquery' ], function () {
        } );
    }
} );</pre>
</li>
<li>使用path配置，指定模块的备选加载路径</li>
<li>全局错误处理回调requirejs.onError，距离：<br />
<pre class="crayon-plain-tag">requirejs.onError = function (err) {
    console.log(err.requireType);
    if (err.requireType === 'timeout') {
        console.log('modules: ' + err.requireModules);
    }
    throw err;
};</pre>
</li>
</ol>
<div class="blog_h1"><span class="graybg">插件</span></div>
<p>RequireJS通过插件机制来扩展其功能，这些插件和require.js分开维护，需要单独下载。</p>
<div class="blog_h2"><span class="graybg">text插件</span></div>
<p>用于加载文本资源，任何以<pre class="crayon-plain-tag">text!</pre> 开头的模块被作为纯文本看待，示例：</p>
<pre class="crayon-plain-tag">require(
    [ "some/module", "text!some/module.html", "text!some/module.css" ],
    function ( module, html, css ) {
        //变量html的内容是some/module.html
        //变量css的内容是some/module.css
    }
);</pre>
<p>text插件使用XHR来加载目标模块，注意CORS问题。</p>
<div class="blog_h2"><span class="graybg">domReady插件</span></div>
<p>可以在页面加载完毕后执行特定的逻辑：</p>
<pre class="crayon-plain-tag">require( [ 'domReady' ], function ( domReady ) {
    domReady( function () {
        //这里的逻辑将在页面加载完毕后执行
    } );
} );

//更加简洁的方式：
require( [ 'domReady!' ], function ( doc ) {
   //这里的逻辑将在页面加载完毕后执行，入参是当前document对象
} );</pre>
<div class="blog_h1"><span class="graybg">FAQ</span></div>
<div class="blog_h3"><span class="graybg">函数requirejs和require有什么区别</span></div>
<p>没有任何区别，仅仅在require这个名称已经被使用的情况下，才需要使用requirejs。</p>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/requirejs-study-note">RequireJS学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/requirejs-study-note/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
