记录:sea.js和require.js配置 与 性能对比

最近有点忙,很久无写博客,记录一下之前的配置require.js和sea.js的配置.(有误有望提出

require.js

文件目录

/app(项目使用js)

/lib(require.js jq存放处)

/plugin(框架对应的功能插件)

require.js比较方便在于,不是amd的模块组件可以通过配置文件进行依赖配置.而且异步加载js 页面加载速度是杠杠的.当然会有点问题的,网速过慢的话,可能会出现js,timeout(可以通过配置解决.

config.js (配置文件)

// 配置信息
requirejs.config({
    // 模块的基准路径
    baseUrl: ‘js/lib‘,
    // 映射不直接放在baseUrl下的模块名
    paths: {
    app: ‘../app‘,
    plugin: ‘../plugin‘,
    jquery: ‘jquery-1.9.1.min‘,
    lazyload: ‘../plugin/jquery.lazyload.min‘,
    base: ‘../‘,
    controller: ‘../app/controller‘,
    model: ‘../app/model‘
    },
    // 为没有使用define()的模块声明依赖关系
    shim: {
    lazyload:{
        deps: [‘jquery‘],
        exports: ‘lazyload‘
    },
    ‘plugin/placeholder‘:{
        deps: [‘jquery‘],
        exports: ‘placeholder‘
    }
    },
    // 设置请求超时时长,设为0时表示不限超时时间
    waitSeconds: 0
});

  官方的文档存在一个 indexMain.js 请求对应的首页js模块 index.js.(大概就以下的感觉)

require([‘config‘], function () {})

请求 ([依赖模块名称],回调());

require([‘config‘], function () {
  require([‘app/index‘]);
});

  然后才在这个index.js模块上对各种模块进行操作,初始化等等操作

define([‘jquery‘,], function($){});

定义模块 ([依赖模块名称],回调(模块返回参数变量));

define([‘jquery‘,], function($){
    $(document).click(function() {
        alert($);
    });
});

  感觉有点多余,所以的采取的配置是这样一回事的直接一个index.js就 直接请求对应的模块为index服务了.

require([‘config‘], function(){
	require([‘jquery‘,‘../common‘], function($){
        $(document).click(function() {
          alert($);
        });
    });
});

  requirejs也支持CMD写法(js里面写require(**)请求js),忘记在哪里看了一篇文章,requirejs 是通过把CMD转换成require([‘jquery‘,‘../common‘])这种模式.所以就不在探究.

sea.js

  好奇心作怪,个人还是测试了sea.js在开发中的使用.一样是模块加载,由于是cmd,懒加载模式下,逻辑思路感觉比较合理?

个人觉得sea的文档比较混乱,require的就比较齐全了.具体自己体验...

文件目录

/app (项目使用js 控制器)

/sea

  /seajs (seajs seajs 配置文件)

  /jquery

    /plugins

  /plugins

针对上次require js挖的坑进行了一次优化目录路径

旧版本seajs 可以通过<script src="./sea.js" data-main="./init"></script> 引进模块控制器,(过去了的旧demo会有这个)

现在是使用 seajs.use([],function(){})来调用模块控制器

seajs.的配置文件需要使用标签引进,<script src="./config.js"></script>

config.js

/**
 * Created by moki on 2015-5-16.
 */
var seaUrl=location.protocol+‘//‘+location.host;
seajs.config({
    // Sea.js 的基础路径
    base: seaUrl+"/res/global/js/sea",
    // 路径配置
    paths: {
        ‘tuonews_reception‘: seaUrl+‘/res/app/tuonews/reception/default/js‘,
        ‘tuonews_user‘: seaUrl+‘/res/app/tuonews/user/default/js‘,
        ‘jq‘:‘jquery‘,
        ‘jq_plugins‘: ‘jquery/plugins‘,
        ‘plugins‘:‘plugins‘
    },
    // 别名配置
    alias: {
        ‘jquery‘: ‘jq/jquery‘,
        ‘$‘: ‘jq/jquery‘
    },
    // 调试模式
    debug: true,
    // 文件编码
    charset: ‘utf-8‘
});

  在页面引进 sea.js 和config.js后 再调用对应的模块控制器,

  在页面中加入对应代码调用模块

  seajs.use([‘jQuery‘,‘common‘],function($){})

                   调用模块      回调

  官方建议回调和模块中不使用seajs.use来请求模块调用,而是使用require;

/**
 * Created by moki on 2015-5-12.
 */
define(function(require,exports,module){  //赋值变量 请求模块
    var $ = require(‘jquery‘);
    $(function (){   //根据节点判断是否需要加载对应的js插件
   var banner = $(‘#banner‘);
       if(banner[0]) {
      require(‘banner‘);
      banner.banner();
    }
    });
});

  seajs的模块化插件 需要改变当前插件

jq ,新版jq本身支持amd模式,在seajs下只需把

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {define( "jquery", [], function () { return jQuery; } );}

改为

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

至于低版本jq 需要定义jq

define(‘jquery‘,[],function(require, exports, module){
	//这里放jQuery源代码
	module.exports = jQuery;
});

制作cmd jq插件

define(‘jquery‘,[],function(require, exports, module){
        var $= require([jQuery]);
	//插件代码
        $.fn.a = function (){}
        //插件代码
}); 

优缺点

基本上seajs和require配置完毕;现在开发中我遇到的问题;

require由于项目运维方向问题,导致整个项目还未正式投入实战当中,估计还会存在坑;

在开发的逻辑思路来说,

seajs是采取 按需请求js, sea的思路会比清晰,(还未压缩js前),控制器不多的时候,通过一个js 来控制多个页面,优势在于可以缓存这个js文件,

requirejs,是先加载依赖文件再编译,所以要多个不同的页面 使用同一个js控制,会令到不同页面都会把大部分无用js加载过来,所以还是有必要拆分多个js.在requirejs下采取cmd模式加载模块,结果如何?(应该本身就不建议这样写,只是方便过渡,所以还是不在考虑当中);

这么一看好像seajs更适合开发?

大家常说requirejs比seajs要快?

seajs会在模块加载后再执行 模块中的require,然而requirejs 是在加载完毕后会执行对应的js

想深究 究竟如何的人 请务必细心看完引用文章

来源      qingbob.com/let-us-talk-about-resource-load/

     http://qingbob.com/let-us-talk-about-resource-load/   让我们再聊聊浏览器资源加载优化

个人认为玉伯聊的比较抽象和宏观,比如标准,概念,机制,社区等。最近一直在做性能优化方面的工作,就自己的经验谈谈require.js和sea.js的异同。这两个加载器和标准没有优劣之分,这里指出的只是差别。具体还是要根据实际情况进行选择

在开始之前我已经假设你对requirejs与seajs语法已经基本熟悉了,如果还没有,请移步这里:

- CMD标准:https://github.com/cmdjs/specification/blob/master/draft/module.md
- AMD标准:https://github.com/amdjs/amdjs-api/blob/master/AMD.md

对比require.js与sea.js,某种意义上说就是对比AMD标准与CMD标准,个人认为两个类库在模块和factory的书写上其实无太大差异,差异在于

  • 模块的加载
  • factory函数的执行。

这里提前说一句,如果你的网站再上线前习惯把所有的模块打包压缩,其实requirejs和seajs并无太大差别。

## 加载差异

这一小节请允许我照搬一个帖子

玉伯转过的一个SeaJS与RequireJS最大的区别,这个帖子原始(不包括后记)的结论是

RequireJS你坑的我一滚啊, 这也就是为什么我不喜欢RequireJS的原因, 坑隐藏得太深了.

SeaJS是异步加载模块的没错, 但执行模块的顺序也是严格按照模块在代码中出现(require)的顺序, 这样才更符合逻辑吧! 你说呢, RequireJS?

而RequireJS会先尽早地执行(依赖)模块, 相当于所有的require都被提前了, 而且模块执行的顺序也不一定100%就是先mod1再mod2
因此你看到执行顺序和你预想的完全不一样! 颤抖吧~ RequireJS!

因为他认为他的测试代码

define(function(require, exports, module) {
    console.log(‘require module: main‘);

    var mod1 = require(‘./mod1‘);
    mod1.hello();
    var mod2 = require(‘./mod2‘);
    mod2.hello();

    return {
        hello: function() {
            console.log(‘hello main‘);
        }
    };
});

运行结果应该是顺序的(sea.js下的结果):

require module: main
require module: mod1
hello mod1
require module: mod2
hello mod2
helo main

而不应该是异步的require.js下:

require module: mod2
require module: mod1
require module: main
hello mod1
hello mod2
helo main

但问题是,为什么"执行模块的顺序"应该是"严格按照模块在代码中出现(require)的顺序"? 并且"这样才更符合逻辑吧"?

如果他以seajs的运行结果来要求requirejs,那requirejs肯定吃亏了。AMD标准从来都没有规定模块的加载顺序,它只是需要保证:

The dependencies must be resolved prior to the execution of the module factory function, and the resolved values should be passed as arguments to the factory function with argument positions corresponding to indexes in the dependencies array.

评论下方有人(jockchou)的回复更切中要害:

我个人感觉requirejs更科学,所有依赖的模块要先执行好。如果A模块依赖B。当执行A中的某个操doSomething()后,再去依赖执行B模块require(‘B‘);如果B模块出错了,doSomething的操作如何回滚? 
很多语言中的import, include, useing都是先将导入的类或者模块执行好。如果被导入的模块都有问题,有错误,执行当前模块有何意义?

楼主说requirejs是坑,是因为你还不太理解AMD“异步模块”的定义,被依赖的模块必须先于当前模块执行,而没有依赖关系的模块,可以没有先后。

想像一下factory是个模块工厂吧,而依赖dependencies是工厂的原材料,在工厂进行生产的时候,是先把原材料一次性都在它自己的工厂里加工好,还是把原材料的工厂搬到当前的factory来什么时候需要,什么时候加工,哪个整体时间效率更高?显然是requirejs,requirejs是加载即可用的。为了响应用户的某个操作,当前工厂正在进行生产,当发现需要某种原材料的时候,突然要停止生产,去启动原材料加工,这不是让当前工厂非常焦燥吗?

这样看来其实两者并无太大差别。

但考虑这样一种业务情况,考虑某一个功能只对登陆用户开放,这样的话requirejs提前把模块加载是否有必要?(因为来到你页面的用户到离开也不会登陆)。

这是非常实际的问题,一个页面可以有非常多的功能,比如登陆、分享、留言、收藏……但不一定每一个来到页面的用户都会使用这些功能,如果都作为页面模块的依赖提前加载的话,对页面一定是一个不小的负担。

但seajs可以即用即加载,比如代码可以这么写

define(function () {

    if (user_login) {
        require(login_feature_module)
    }    

    document.body.onclick = function () {
        require(show_module)
    }
})

我同意这句话:

很多语言中的import, include, useing都是先将导入的类或者模块执行好。如果被导入的模块都有问题,有错误,执行当前模块有何意义?

但个人觉得考虑到页面的性能,可以考虑将要导入模块的懒加载(Lazy load)。

你会不会觉得我上面说的懒加载是一种天方夜谭?

但然不是,你去看看现在的人人网个人主页看看

图中标注的“与我相关”、“相册”、“分享”都是在点击之后才加载对应的模块

Facebook的情况更为严重,不仅要考虑内部不同团队的功能模块,还要考虑第三方的功能模块。

早在09年,他们就是用了一套静态资源管理方案(Static Resource Management),用于管理一个功能所需要的js/css静态文件:

简单来说,就是由页面上有没有功能所需的html片段,来决定是否加载和打包功能所需的js与style。也就是说静态文件需要通过html“声明”之后才可用。

具体可以参考这里:Frontend Performance Engineering in Facebook : Velocity 2009

## 执行差异

为了增强对比,我们在定义依赖模块的时候,故意让它的factory函数要执行相当长的时间,比如1秒:

// dep_A.js定义如下,dep_B/dep_C定义同理

define(function(require, exports, module) {

    (function(second) {
        var start = +new Date();
        while (start + second * 1000 > +new Date()) {}
    })(window.EXE_TIME);

    // window.EXE_TIME = 1;此处会连续执行1s

    exports.foo = function() {
        console.log("A");
    }
})

// main中同时加载三个相同模块

//require.js:
require(["dep_A", "dep_B", "dep_C"], function(A, B, C) {

});

//sea.js:
define(function(require, exports, module) {

    var mod_A = require("dep_A");
    var mod_B = require("dep_B");
    var mod_C = require("dep_C");
});

requirejs加载的瀑布图:

seajs加载的瀑布图:

如果把一个模块的执行拆分为执行define和执行factory函数的话(对requirejs和seajs都适用),从上图可以看出:

  • requirejs:一个模块的factory函数执行是紧跟随在define(也就是Evaluate Script脚本模块文件)之后
  • seajs: 执行一个模块的factory函数需要等待所有模块define完毕。

重点不是这些,我想说的是我在seajs中看到一个闪光点。

在上面一节中我提到了懒加载模块,在加载模块的时候需要1. 临时请求模块文件 ; 2. 执行factory函数。

但如果我们在载入页面时仅仅是执行把懒加载的模块的define(从上面两个图可以看出define的代价是非常小的),而设法不执行factory函数。

那么在真正需要懒加载的时候只要执行factory函数即可。这样不是能够让模块响应更及时,更靠谱?

这是可以实现的。但技术细节就不赘述了。这可以作为优化模块加载的一种方案。

那么也看看上述引用文章的后记吧

注意我这里说的是执行(真正运行define中的代码)模块, 而非加载(load文件)模块.
模块的加载都是并行的, 没有区别, 区别在于执行模块的时机, 或者说是解析.

为了说明阻塞的问题, 翠花上图


SeaJS的懒执行

RequireJS的预执行

注意图中巨大的pinyin-dict.js模块, 取自pinyin.js, 复制了N次后以增加它的"重量", 增强演示效果, 大家有兴趣的话可以亲手试试.

可以很明显的看出RequireJS的做法是并行加载所有依赖的模块, 并完成解析后, 再开始执行其他代码, 因此执行结果只会"停顿"1次, 完成整个过程是会比SeaJS要快.

而SeaJS一样是并行加载所有依赖的模块, 但不会立即执行模块, 等到真正需要(require)的时候才开始解析, 这里耗费了时间, 因为这个特例中的模块巨大, 因此造成"停顿"2次的现象, 这就是我所说的SeaJS中的"懒执行".

最后感谢大家的各种意见建议, 我这里并没有说SeaJS与RequireJS哪个更好一些, 仅仅是为了说明下他们的区别, 各种取舍请大家根据实际情况来定, 希望能帮到大家.

看到这里,估计都明白了,针对情景不一样,最后在于大家的取舍了.

时间: 2024-12-24 07:00:15

记录:sea.js和require.js配置 与 性能对比的相关文章

sea.js与require.js的区别

随着ES6标准的module出台渐渐会退出历史舞台 首先原理上的区别 sea.js遵循CMD规范.书写方式类似node.js的书写模板代码.依赖的自动加载,配置的简洁清晰.说白了就是懒加载. require.js遵循AMD规范,CMD和AMD基本相同,最大的区别是就CMD是懒加载,AMD是预加载. 简单来说,就是sea.js属于懒加载,require.js属于预加载. 在这里,顺便扩展一下预加载和懒加载的优缺点 预加载:当第一次访问时将所有的文件加载出来 优点:第一次访问完成以后, 再次访问的速

PHP加载大文件时require和file_get_contents的性能对比

在开发过程中发现,用require来加载一个很大(几百K,甚至几兆)的配置文件时,会造成响应超时.如果把这个配置文件的内容序列化后,用file_get_contents获取文件然后反序列化的方法来加载,就会快很多. 经过近两周的研究,大概知道了其中的原因. 首先,还从PHP的流程说起,PHP其实有两个流程,一个是启动的流程,一个是响应请求的流程.PHP作为Apache的一个模块,向Apache注册了两个函数,一个是Aapche启动的时候运行的函数:sapi_startup:一个是Apache接收

require.js与sea.js的区别

hi,感谢各位读者能够阅读我的文章. 下面为大家讲解一下require.js和sea.js的区别.纯属个人意见,不喜勿喷. 首先原理上的区别 sea.js遵循CMD规范.书写方式类似node.js的书写模板代码.依赖的自动加载,配置的简洁清晰.说白了就是懒加载. require.js遵循AMD规范,CMD和AMD基本相同,最大的区别是就CMD是懒加载,AMD是预加载. 简单来说,就是sea.js属于懒加载,require.js属于预加载. 在这里,顺便扩展一下预加载和懒加载的优缺点 预加载:当第

require.js 源码解读——配置默认上下文

首先,我们先来简单说一下,require.js的原理: 1.载入模块? 2.通过模块名解析出模块信息,以及计算出URL? 3.通过创建SCRIPT的形式把模块加载到页面中.? 4.判断被加载的脚本,如果发现它有依赖就去加载依赖模块.如果不依赖其它模块,就直接执行factory方法 ?5.等所有脚本都被加载完毕就执行加载完成之后的回调函数. 从今天起,我们跟着我们简单的例子,通过跟踪代码,来了解require.js的源码. 1 <!DOCTYPE html> 2 <html lang=&q

require.js配置路径的用法和css的引入

前端开发在近一两年发展的非常快,JavaScript作为主流的开发语言得到了前所未有的热捧.大量的前端框架出现了,这些框架都在尝试着解决一 些前端开发中的共性问题,但是实现又不尽相同.通常一般的前端加载js文件都是这样 : <script type="text/javascript" src="js/js1.js"></script> <script type="text/javascript" src="

require.js 基础使用方法记录

require.js作为javsscript的一种模块化编程规范,异步加载模块,主要应用于浏览器端,异步加载js文件,让浏览器不会因为在加载js文件而失去响应. 一.开始 目录结构: 首先要加载require.js <!-- ***.html--> <script data-main="js/app.js" src="js/require.js" defer></script> app.js即是入口文件,我们在里面加载math.j

JavaScript模块化-require.js,r.js和打包发布

在JavaScript模块化和闭包和JavaScript-Module-Pattern-In-Depth这两篇文章中,提到了模块化的基本思想,但是在实际项目中模块化和项目人员的分工,组建化开发,打包发布,性能优化,工程化管理都有密切的关系,这么重要的事情,在JavaScript大行其道的今天,不可能没有成熟的解决方案,所以从我的实践经验出发,从模块化讲到工程化,分享一下自己的经验. 这篇文章主要是讲require.js和r.js在项目中的使用,不会涉及到工程化问题,对此熟悉的看官可以略过此文.对

Javascript模块化编程(三):require.js的用法

作者: 阮一峰 日期: 2012年11月 7日 这个系列的第一部分和第二部分,介绍了Javascript模块原型和理论概念,今天介绍如何将它们用于实战. 我采用的是一个非常流行的库require.js. 一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代码,相信很多人都见过. <script src="1.js"></s

Require.js、Angular.js整合

Require.js 详见: 初识Require.js 解密Require.js Angular.js 详见: 初识Angular.js之爱恨情仇 整合Require.js.Angular.js 配置 在Requirejs中配置angular.js. require-main.js // 配置 requirejs.config({ ... paths: { 'jquery': 'libs/jquery-2.1.3/jquery.min', 'angular': 'libs/angular-1.3