seajs研究一二三

出自大名鼎鼎玉伯之手的seajs在业界引起了广泛的反响,好评如潮,如今我也加入到了其中.

到今天在项目中使用seajs也有几个月了,不久前开始正式研究seajs源码,终于准备发这篇博客了,也是我在博客园的第一篇博客(*^__^*) .怪鸡冻的.那么接下来进入正题.

一.seajs初步理解(seajs内部执行流程)

1).use或data-main(用户手动)

2).rquest(动态插入script标签)
3).扫描模块中的factory.toString(),根据一个很长的正则去查找use进来的模块中rquire的所有模块(即require括号里的那个字符串,也即依赖模块)
4).将第三步中查找出来的模块再进行2、3步操作(如果有),直到所有模块(包括所有依赖模块)都加载完毕,在此期间已经做好了依赖分析
5).至此所有模块均已就绪,按照之前分析好的依赖关系,按顺序执行各模块中define方法中传入的factory函数
小结:
1).发现源码中对路径的处理花了很多笔墨,尚需研究

2).正因为动态插入script标签不会产生阻塞,即可以并行下载模块,通过依赖分析,保证了模块的顺序执行,最终提高了页面性能,当然模块少的时候显示不出其效用(甚至慢了),但是模块越多其作用越明显。

3).引用拔赤的话:seajs提供“方法和思路”,而jquery、yui等则提供工具。seajs需要“学习”,而jquery更多的则是需要“查阅”


二.再理解

当seajs加载完一个模块时,会立即扫描factory.toString(),这件事如何触发的呢,通过阅读源码发现是利用了节点的onload和onerror事件,

1 node.onload = node.onerror = node.onreadystatechange = function() {
2     if (READY_STATE_RE.test(node.readyState)) {
3      //...do something
4       callback()//扫描
5     }
6   }

其中老的webkit和firefox还有一个问题:当加载css失败,不会触发onerror事件,seajs通过设置定时器不断访问node.sheet判断加载是否完成(包括失败的情况)

 


三.路径研究

发现它考虑到了base标签的问题,其中有一句代码

1 baseElement?
2 head.insertBefore(node, baseElement) :
3 head.appendChild(node)

根据它的意思,应该是要避开base影响seajs本身的基础路径,但是我经过测试(不使用seajs),通过js动态在base标签前插入script标签,这个新的script的src还是会带上base标签指定的路径,后用seajs测试,发现script节点的src值是绝对路径(http开头的那种),并以此为前缀动态插入script标签引进新的模块,而绝对路径是不受base标签影响的.那么它考虑base标签是不是有些多余,这个不得而知.准备去社区问问看.

今天又针对路径的问题进行了一番测试,有这么几种使用方式:

  1. seajs的data-main
  2. seajs.use
  3. define中的require

不过它们的参数,也就是模块路径,原理是一致的.上图,大家一看就都明白了

下面是从官网摘来的片段:

---------------------------------------------我是万恶的分割线-----------------------------------------------------------

模块系统的基础路径即 base 的默认值,与 sea.js 的访问路径相关:
如果 sea.js 的访问路径是:
  http://example.com/assets/sea.js

则 base 路径为:
  http://example.com/assets/
除了相对和顶级标识之外的标识都是普通路径。普通路径的解析规则,和 HTML 代码中的<script src="..."></script> 一样,会相对当前页面解析。


// 假设当前页面是 http://example.com/path/to/page/index.html

// 绝对路径是普通路径:require.resolve('http://cdn.com/js/a');
  // => http://cdn.com/js/a.js

// 根路径是普通路径:require.resolve('/js/b');
  // => http://example.com/js/b.js

// use 中的相对路径始终是普通路径:seajs.use('./c');
  // => 加载的是 http://example.com/path/to/page/c.js

seajs.use('../d');
  // => 加载的是 http://example.com/path/to/d.js
提示:

小结:
  1. 顶级标识始终相对 base 基础路径解析。
  2. 绝对路径和根路径始终相对当前页面解析。
  3. require 和 require.async 中的相对路径相对当前模块路径来解析。
  4. seajs.use 中的相对路径始终相对当前页面来解析。

-------------------------------------------我也是万恶的分割线---------------------------------------------------
下面是我自己的test:

其中,seajs可以是外网的,那么相应地base路径也是外网的,见下图


 

posted on 2013-04-25 19:30  雲石  阅读(878)  评论(0编辑  收藏  举报