requirejs:性能优化-及早并行加载

为了提高页面的性能,通常情况下,我们希望资源尽可能地早地并行加载。这里有两个要点,首先是尽早,其次是并行。

通过data-main方式加载要尽可能地避免,因为它让requirejs、业务代码不必要地串行起来。下面就讲下如何尽可能地利用浏览器并行加载的能力来提高性能。

低效串行:想爱但却无力

最简单的优化,下面的例子中,通过两个并排的script标签加载require.js、main.js,这就达到了require.js、main.js并行加载的目的。

但这会有个问题,假设main.js依赖了jquery.js、anonymous.js(如下代码所示),那么,只有等main.js加载完成,其依赖模块才会开始加载。这显然不够理想,后面我们会讲到如何避免这种情况,下面是简单的源码以及效果示意图。

demo.html

<!DOCTYPE html>

<html>

<head></head>

<body>

<h1>main.js、anynomous.js串行加载</h1>



<script type="text/javascript" src="js/require.js"></script>

<script type="text/javascript" src="js/main.js"></script>



</body>

</html>

js/main.js:

require(['js/anonymous'], function(Anonymous) {

    alert('加载成功');

});

js/anonymous.js:

define(['js/jquery'], function() {

    console.log('匿名模块,require直接报错了。。。');

    return{

        say: function(msg){

            console.log(msg);

        }

    }

});

最终效果: Alt text

简单匿名:一条走不通的路

正常情况下,假设页面里有如下几个<script>标签,现代浏览器就会并发请求文件,并顺序执行。但在requirejs里,如果这样做的话,可能会遇到一些意料之外的情况。如下所示,四个并排的标签,依次请求了require.jsjquery.jsanonymous.jsmain.js

demo.html:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>demo</title>

</head>

<body>

<h1>requirejs并行加载例子</h1>



<script type="text/javascript" src="js/require.js"></script>

<script type="text/javascript" src="js/jquery.js"></script>

<script type="text/javascript" src="js/anonymous.js"></script>

<script type="text/javascript" src="js/main.js"></script>



</body>

</html>

预期中,资源会并行加载,但实际上,你会在控制台里看到下面的错误日志。

Alt text

为什么呢?对于requirejs来说,上面的js/anonymous.js是一个匿名的模块,requirejs对它一无所知。当你在main中告诉requirejs说我要用到js/anonymous这个模块时,它就傻眼了。所以,这里就直接给你报个错误提个醒:不要这样写,我不买账。

那么,及早并行加载的路是否走不通了呢?未必,请继续往下看。

答案就在身边:注册为命名模块的jquery

简单改下上面的例子,比如这样,然后。。它就行了。。

<script type="text/javascript" src="js/require.js"></script>

<script type="text/javascript" src="js/jquery.js"></script>

<script type="text/javascript" src="js/main.js"></script>

Alt text

原因很简单。因为jquery把自己注册成了命名模块。requirejs于是就认得jquery了。

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {

    define( "jquery", [], function () { return jQuery; } );

}

jquery的启发:起个好名字很重要

上面我们看到,给模块起个名字,将匿名模块改成命名模块(named module),就开启了我们的并行加载之旅。从这点看来,起名字真的很重要。

那么我们对之前的例子进行简单的改造。这里用了个小技巧,利用命名模块js/name-module.js来加载之前的匿名模块js/anonymous.js。可以看到,requirejs不报错了,requirejs跟name-module.js也并行加载了。

demo.html:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">



<title>demo</title>

</head>

<body>

<h1>并行加载requirejs、jquery</h1>



<script type="text/javascript" src="js/require.js"></script>

<script type="text/javascript" src="js/jquery.js"></script>

<script type="text/javascript" src="js/name-module.js"></script>

<script type="text/javascript" src="js/main.js"></script>



</body>

</html>

js/name-module.js

define('name-module', 'js/anonymous', [], function() {

    return {

        say: function(msg){

            alert(msg);

        }

    };

});

最终效果图: 

Alt text

通往希望之门:解决anonymous模块的串行问题

如果你能耐着性子看到这一节,说明少年你已经发现了上一节很明显的一个问题:尽管name-module.js并行加载了,但anonymou.js其实还是串行加载,那做这个优化还有什么意义? 

Alt text

没错,如果最终优化效果这样的话,那是完全无法接受的。不卖关子,这个时候就要请出我们的requirejs打包神器r.js。通过打包优化,将anonymous.jsname-module.js打包生成一个文件,就解决了串行的问题。

1、安装打包工具

npm install -g requirejs

2、创建打包配置文件,注意,由于jquery.js比较通用,一般情况下会单独加载,所以从打包的列表里排除

{

    "appDir": "./",  // 应用根路径

    "baseUrl": "./",  // 

    "dir": "dist",  // 打包的文件生成到哪个目录

    "optimize": "none", // 是否压缩

    "modules": [

        {

            "name": "js/name-module",

            "exclude": [

                "jquery"  // 将jqury从打包规则里排除

            ]

        }

    ]

}

3、运行如下命令打包

r.js -o ./build.js

4、打包后的name-module,可以看到,匿名模块也被打包进去,同时被转换成了命名模块

define('js/anonymous',['jquery'], function() {

    console.log('匿名模块,require直接报错了。。。');

    return{

        say: function(msg){

            console.log('anonymous: '+msg);

        }

    }

});

define('js/name-module', ['js/anonymous'], function() {

    return {

        say: function(msg){

            alert('name module: '+msg);

        }

    };

});

5、再次访问demo.html,很好,就是我们想要的结果 

Alt text

写在后面

上面主要提供了及早并行加载的思路,但在实际利用requirejs打包的过程中,还会遇到一些需要小心处理的细节问题,当然也有一些坑。后面有时间再总结一下。

你可能感兴趣的:(requirejs)