简单学习requirejs

前天某个群里的人问了一句:我怎么没感觉到用了require.js的好处,反而比平时更麻烦了,他想知道为啥要用requirejs。我想,因为他可能一直在一个人写代码吧。

模块化在其他开发过程中几乎是非常寻常的事儿,倒是到了前端开发的时候就变得特殊了,初学的时候几乎不管这些东西,但是随着页面的交互逻辑越来越复杂,JS文件之间依赖关系越来越多,开发者慢慢变多,模块化肯定是最成熟的解决方案。

模块化必然需要规范,常见的规范有AMD CMD CommonJS,nodejs采用了CommonJS的规范,requirejs为了解决浏览器端的模块化开发,慢慢产出了AMD规范。后来玉伯大大在使用requirejs的过程中意识到了AMD在开发过程中的一些问题,自己开发了seajs,慢慢产出CMD规范。

异步模块定义(AMD)

异步模块定义是一种对模块的定义,使模块和它的依赖可以被异步的加载,但又按照正确的顺序。

开始

先来理解requirejs是怎么开始工作的,看下面 的代码

1
<script src="scripts/require.js" data-main="scripts/app.js"></script>

这个是加载requirejs的script,requiresjs在加载完成之后会去读取自己的data-main属性,然后根据里面的值去加载相关的模块,所以data-mian对应的模块就相当于c语言的main函数。

requirejs的Api介绍

requirejs有三个主要的函数:
1.define
2.require
3.config

分别介绍三个函数的作用就能大体理解requirejs如何使用了,都是官网文档看的,稍微总结下。

配置

requirejs.config函数用于定义requirejs的配置参数

baseUrl——用于加载模块的根路径。
paths——用于映射不存在根路径下面的模块路径。
shims——配置在脚本/模块外面并没有使用RequireJS的函数依赖并且初始化函数。假设underscore并没有使用 RequireJS定义,但是你还是想通过RequireJS来使用它,那么你就需要在配置中把它定义为一个shim。
deps——加载依赖关系数组

定义和使用模块

define的作用是定义模块,不同模块在不同作用域里,避免变量污染,在一个没有依赖的模块里,define函数的第一个参数就是模块的主体,可以在模块内部执行初始化代码然后返回对象。

1
2
3
4
5
6
7
8
define(function () {
    //Do setup work here

    return {
        color: "black",
        size: "unisize"
    }
});

如果是一个有依赖的模块,第一个参数是一个数组,里面是依赖的模块。第二个参数是上面的匿名函数,参数是依赖的模块名。

1
2
3
4
5
6
7
8
9
10
11
12
define(["./cart", "./inventory"], function(cart, inventory) {
        //return an object to define the "my/shirt" module.
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

这个例子里面,./cart 和 ./inventory 分别对应和该模块同目录下的 cart.js inventory.js



上面的模块返回的都是object,也可以返回function。


require函数就简单多了,通过requirejs可以去加载一个模块。


1
2
3
4
require(['jquery'], function ($) {
    //jQuery was loaded and can be used now
});

支持AMD的库

现在很多库都支持amd规范

如 MooTools 、 jQuery 、 qwery 、 bonzo。
甚至angularjs也能和requirejs结合起来提高团队开发效率。

优劣

requirejs实现了web端的模块化,确实提高了开发效率,但是他想通吃前后端。
并且requirejs遵循的AMD规范是预执行依赖模块,seajs则是懒执行。

预执行在这里绝对不是好方法

懒执行的SeaJS只会在真正需要使用(依赖)模块时才执行该模块
SeaJS是异步加载模块的没错, 但执行模块的顺序也是严格按照模块在代码中出现(require)的顺序,而requirejs则是加载完毕即执行,而且模块执行顺序不一定是按照你想的。

所以玉伯大大说:“requirejs是有明显的bug,seajs是明显没有bug”。多么自信的豪言壮语,源自于seajs的优势。