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打包的过程中,还会遇到一些需要小心处理的细节问题,当然也有一些坑。后面有时间再总结一下。

相关文章
|
2天前
|
缓存 监控 JavaScript
优化策略:提升Vue应用的性能和加载速度
【4月更文挑战第23天】本文探讨了优化Vue应用的策略,包括代码层面(精简代码、组件拆分、计算属性和侦听器)、路由懒加载、数据懒加载与防抖节流、图片和资源压缩及CDN、缓存机制的利用,以及使用Vue Devtools和性能分析工具进行监控与调试。通过这些方法,可以提升Vue应用的性能和加载速度,确保用户获得流畅体验。
|
3月前
|
缓存 JavaScript 前端开发
Vue项目卡顿慢加载?这些优化技巧告诉你!(一)
Vue项目卡顿慢加载?这些优化技巧告诉你!
|
3月前
|
缓存 JavaScript 前端开发
js性能优化
减少DOM操作:
30 0
|
3月前
|
缓存 JavaScript 前端开发
Vue项目卡顿慢加载?这些优化技巧告诉你!(二)
Vue项目卡顿慢加载?这些优化技巧告诉你!(二)
|
9月前
|
前端开发 JavaScript Serverless
前端工程化的前端性能的性能优化方案的渲染层面优化之CSS/JS优化
渲染是一种非常重要的前端性能优化方案,因为它可以在不同的环境中提高网页的响应速度和可接受性。
64 2
|
7月前
|
机器学习/深度学习 缓存 Linux
很底层的性能优化:让CPU更快地执行你的代码
很底层的性能优化:让CPU更快地执行你的代码
|
10月前
|
缓存 JavaScript 前端开发
【 Vue3 性能优化】页面加载性能 与 更新性能
【 Vue3 性能优化】页面加载性能 与 更新性能
640 0
|
10月前
|
存储 Web App开发 监控
Js中的垃圾回收及V8引擎的优化
Js中的垃圾回收及V8引擎的优化
236 0
|
10月前
|
存储 JavaScript 算法
Vue3 是如何通过编译优化提升框架性能的?
Vue3 是如何通过编译优化提升框架性能的?
133 0
|
缓存 JavaScript 前端开发
性能优化之关键渲染路径
分别从浏览器架构和最新的渲染引擎介绍了关于页面渲染的相关概念。对应连接如下。 • 页面是如何生成的(宏观角度) • Chromium 最新渲染引擎--RenderingNG • RenderingNG中关键数据结构及其角色 而今天的主角是{关键渲染路径| Critical Rendering Path}。它是影响页面在加载阶段的主要标准。