您的位置:阿里西西 > 前端技术 > 脚本技术 > 详细内容

RequireJS、SeaJS的区别

  本站整理   互联网   2015-08-03   点击:   我要评论
引用自知乎(卢勃)

1. RequireJS的异步模块加载迎合了浏览器端JS程序员固有的异步思维,学习成本低
--------------------------------
Sea.js的主页中写到:
  • Sea.js 遵循 CMD 规范,可以像 Node.js 一般书写模块代码
  • 依赖的自动加载、配置的简洁清晰,可以让我们更多地享受编码的乐趣
两年前,我看到Sea.js这样的自我描述,第一感觉是:为什么浏览器的JS编程和NodeJS相仿就是优雅呢?

那么,来讨论RequireJS和Sea.js的学习成本问题

如RequireJS中依赖模块:
require(['jquery','创建了全局变量的module'],function($,b){
	//既然我在开头明确声明依赖需求,那可以确定在执行这个回调函数时,依赖肯定是已经满足了
	//所以,放心地使用吧
})

而Sea.js中表现为:
define(function(require,exports,modules){
	var $ = require('jquery')
	$.get('http://www.zhihu.com')
	//传统JS程序员的思维:
	//“咦,好神奇,JS加载不应该是异步的么,怎么我一说要依赖,jquery就自己跳出来了?”
})

所以,是“理所应当”容易理解,还是变魔术容易理解呢?

2. RequireJS的实现方式符合JS一般执行流程
--------------------------------
当我们看到RequireJS的接口,
require(['a','b'],function(){
//Do something
})
实际做的事情是:
  1. require函数检查依赖的模块,根据配置文件,获取js文件的实际路径
  2. 根据js文件实际路径,在dom中插入script节点,并绑定onload事件来获取该模块加载完成的通知。
  3. 依赖script全部加载完成后,调用回调函数
以上步骤是容易想象的

而Sea.js在调用
define('a',function(require,exports,modules){
	var b = require('b')
})
时,
  1. 通过回调函数的Function.toString函数,使用正则表达式来捕捉内部的require字段,找到require('jquery')内部依赖的模块jquery
  2. 根据配置文件,找到jquery的js文件的实际路径
  3. 在dom中插入script标签,载入模块指定的js,绑定加载完成的事件,使得加载完成后将js文件绑定到require模块指定的id(这里就是jquery这个字符串)上
  4. 回调函数内部依赖的js全部加载(暂不调用)完后,调用回调函数
  5. 当回调函数调用require('jquery'),即执行绑定在'jquery'这个id上的js文件,即刻执行,并将返回值传给var b
这种用正则表达式捕捉require内部依赖模块的方式,使得无法利用尚未执行的回调函数中的js运行环境,导致require函数的内部只能将依赖的模块名称硬编码,就不能写下面这样的代码了
define('a',function(require,exports,modules){
    var b = require('Us'+'er')
})
而只能写成
define('a',function(require,exports,modules){
    var b = require('User')
})
而以上Sea.js最根本的原理在Sea.js的文档中居然毫无踪影!
“你变了精彩的魔术,我们会为你喝彩。但你想让我们信任你,你得主动解释魔术的奥秘。否则我会觉得自己被耍了。”

所以就引来了下一条:

3. Sea.js的文档立足高度高,未提及重点细节
--------------------------------
其实如果像上一段一样,将Sea.js的核心原理进行简单解释,有基本知识的JS程序员大概是可以“五分钟上手Sea.js”的,但在官方文档中,这些都只字不提。

Sea.js - 官方文档 中开始在讲要解决的问题和问题解决后的价值,OK,能开始有意识尝试使用Sea.js的JS程序员想必是遇到模块错综复杂的问题需要解决了。

然后给了看起来同步加载的,显得很魔术的示例代码(“哇,好厉害的赶脚!大牛,所以这是怎么做到的呢?”)
// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var $ = require('jquery');
  var Spinning = require('./spinning');

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

});

接着就直接开讲API和约定了。(“谁来照顾下我的好奇心呢!说好的我今天对你爱理不理,明天你让我高攀不起呢!”)

这种感觉好像是数学老师刚刚还在讲微积分的历史沿革及其重要性,低头看了眼手机,抬起头就已经在讲三重积分了呢!(捂脸)

这也是我通篇充满了对作者的怨恨的原因。当时初闻Sea.js,发现是国人的作品耶,恩,网上评价不错,立马学习,没有理由地想从RequireJS迁移到Sea.js(RequireJS在一边问:“我做错什么了吗?做错了我改嘛”)。但看文档尝试阅读了好几次(没有看代码,骂我吧),还是觉得很魔术,觉得是雾里看花。
今天不知从哪里瞟了一眼,说是Sea.js通过正则表达式来找回调函数内容中的require来确定加载的函数,然后一看代码果然是,顿时火从心燃,不写篇文章吐槽绝不能灭火(想象抛妻弃子追寻真爱,最终发现真爱原是博爱的感觉)。

技术文档应当切中要害,节约读者时间,而不是故作深沉。将简单的复杂化怎么也不应该是程序员的作风。

“为世界和平稳定,家庭的幸福快乐”不能停留在嘴上说说,最终要落到实处。

4. Sea.js部署优化工具尚未完善
--------------------------------
好吧,这是听大家在上面说的,我没怎么用Sea.js,还没遇到这样的问题

最后想对 @李翌 的回答中,关于懒加载的部分表达下我的理解

LazyLoad的优势体现在:仅当资源需要被使用前加载资源。在RequireJS和Sea.js中表现为,在回调函数调用前加载js脚本资源。

RequireJS和Sea.js在资源加载的时间点都是一样的,所以论“懒”的程度都是一样的。差别仅仅在于加载的脚本什么时候执行。RequireJS的依赖模块在回调函数执行前执行完毕,而Sea.js的依赖模块在回调函数执行require时执行。

而回调函数希望实现的目标就好比“事务的原子性”,仅当整个回调函数结束才算完成了目标。那么既然整个回调函数的执行时间是恒定的,那么个人认为脚本加载的时间到底耗费在回调前还是回调时,并没有本质的差别。如果不认同是否本质相同,那么至少也没有谁更懒的区别。



更多关于 的文章
·上一篇:jQuery回调对象
·下一篇:js数组的操作
会员评论所有会员评论

  

相关排行总榜

网页教程

站长文章

特效排行