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

相关文章
|
7月前
|
缓存 监控 JavaScript
探讨优化Vue应用性能和加载速度的策略
【5月更文挑战第17天】本文探讨了优化Vue应用性能和加载速度的策略:1) 精简代码和组件拆分以减少冗余;2) 使用计算属性和侦听器、懒加载、预加载和预获取优化路由;3) 数据懒加载和防抖节流处理高频事件;4) 图片压缩和选择合适格式,使用CDN加速资源加载;5) 利用浏览器缓存和组件缓存提高效率;6) 使用Vue Devtools和性能分析工具监控及调试。通过这些方法,可提升用户在复杂应用中的体验。
87 0
|
4月前
|
前端开发 JavaScript Java
hyengine 编译问题之复用脚本引擎如何解决
hyengine 编译问题之复用脚本引擎如何解决
|
4月前
|
存储 JavaScript Java
hyengine 解释问题之wasm引擎性能瓶颈如何解决
hyengine 解释问题之wasm引擎性能瓶颈如何解决
|
4月前
|
前端开发 JavaScript UED
现代前端开发中的动态组件加载与性能优化
传统的前端应用加载所有组件可能会导致性能问题和用户体验下降。本文讨论了现代前端开发中采用动态组件加载的策略,通过异步加载和按需渲染优化页面加载速度和资源利用效率。
|
前端开发 JavaScript Serverless
前端工程化的前端性能的性能优化方案的渲染层面优化之CSS/JS优化
渲染是一种非常重要的前端性能优化方案,因为它可以在不同的环境中提高网页的响应速度和可接受性。
91 2
|
机器学习/深度学习 缓存 Linux
很底层的性能优化:让CPU更快地执行你的代码
很底层的性能优化:让CPU更快地执行你的代码
|
缓存 JavaScript 前端开发
【 Vue3 性能优化】页面加载性能 与 更新性能
【 Vue3 性能优化】页面加载性能 与 更新性能
955 0
|
存储 JavaScript 算法
Vue3 是如何通过编译优化提升框架性能的?
Vue3 是如何通过编译优化提升框架性能的?
188 0
|
缓存 JavaScript 前端开发
性能优化之关键渲染路径
分别从浏览器架构和最新的渲染引擎介绍了关于页面渲染的相关概念。对应连接如下。 • 页面是如何生成的(宏观角度) • Chromium 最新渲染引擎--RenderingNG • RenderingNG中关键数据结构及其角色 而今天的主角是{关键渲染路径| Critical Rendering Path}。它是影响页面在加载阶段的主要标准。
|
存储 缓存 编解码
「性能优化系列」不使用第三方库,Bitmap的优化策略
在Android3.0到Android7.0,Bitmap对象和像素都是放置到Java堆中,这个时候即使不调用recycle,Bitmap内存也会随着对象一起被回收。虽然Bitmap内存可以很容易被回收,但是Java堆的内存有很大的限制,也很容易造成GC。 在Android8.0的时候,Bitmap内存又重新放置到了Native中。 Bitmap造成OOM很多时候也是因为对Bitmap的资源没有得到很好的利用,同时没有做到及时的释放。
380 0