Javascript文件加载:LABjs和RequireJS
openkk 13年前
<p> 传统上,加载 Javascript 文件都是使用<script>标签。</p> <p> 就像下面这样:</p> <blockquote> <p><script type="text/javascript" src="example.js"></script></p> </blockquote> <p style="text-align:center;"><img title="20111003_131533_1.jpg" border="0" alt="20111003_131533_1.jpg" src="https://simg.open-open.com/show/9f5edbe317c55de9bac2ee146767fbba.jpg" /></p> <p> <script>标签很方便,只要加入网页,浏览器就会读取并运行。但是,它存在一些严重的缺陷。</p> <p> <strong>(1)严格的读取顺序。</strong>由于浏览器按照<script>在网页中出现的顺序,读取 Javascript 文件,然后立即运行,导致在多个文件互相依赖的情况下,依赖性最小的文件必须放在最前面,依赖性最大的文件必须放在最后面,否则代码会报错。</p> <p> <strong>(2)性能问题。</strong>浏览器采用"同步模式"加载<script>标签,也就是说,页面会"堵塞"(blocking),等待 javascript 文件加载完成,然后再运行后面的 HTML 代码。当存在多个<script>标签时,浏览器无法同时读取,必须读取完一个再去读取另一个,造成读取时间大大延长,页面响应缓慢。</p> <p> 为了解决这些问题,可以使用 DOM 方法,动态加载 Javascript 文件。</p> <blockquote> <p>function loadScript (url){</p> <p>var script = document.createElement ("script");</p> <p>script.type = "text/javascript";</p> <p>script.src = url;</p> <p>document.body.appendChild (script);</p> <p>}</p> </blockquote> <p> 这样做的原理是,浏览器即时创造出一个<script>标签,然后"异步"读取 Javascript 文件。这样不会造成页面堵塞,但会造成另外一个问题:这样加载的 Javascript 文件,不在原始的 DOM 结构之中,因此在 DOM-ready(DOMContentLoaded)事件和 window.onload 事件中指定的回调函数对它无效。</p> <p> 外部函数库 <a href="/misc/goto?guid=4958192400979693005" target="_blank">LABjs</a> 和 <a href="/misc/goto?guid=4958184194212155366" target="_blank">RequireJS</a>,可以帮助我们更有效地管理 Javascript 加载。</p> <p> 下面根据 <a href="/misc/goto?guid=4958192402405466122" target="_blank">ScriptJunkie</a> 的文章,举一个最简单的例子,来说明这两个函数库的基本用法。更高级的用法,请参阅它们的文档。</p> <blockquote> <p><script src="script1.js"></script></p> <p><script src="script2-a.js"></script></p> <p><script src="script2-b.js"></script></p> <p><script type="text/javascript"></p> <p>initScript1 ();</p> <p>initScript2 ();</p> <p></script></p> <p><script src="script3.js"></script></p> <p><script type="text/javascript"></p> <p>initScript3 ();</p> <p></script></p> </blockquote> <p> 上面这段代码,将依次加载 4 个 javascript 文件:script1.js、script2-a.js、script2-b.js 和 script3.js。在加载完前三个文件后,运行两个函数 initScript1 ()和 initScript2 ();加载完第四个文件后,再运行函数 initScript3 ()。</p> <p> 下面,用 LABjs 对其进行改写:</p> <blockquote> <p><script src="LAB.js"></script></p> <p><script type="text/javascript"></p> <p>$LAB</p> <p>.script ("script1.js") .wait ()</p> <p>.script ("script2-a.js")</p> <p>.script ("script2-b.js")</p> <p>.wait (function (){</p> <p>initScript1 ();</p> <p>initScript2 ();</p> <p>})</p> <p>.script ("script3.js")</p> <p>.wait (function (){</p> <p>initScript3 ();</p> <p>});</p> <p></script></p> </blockquote> <p> 首先,$LAB 对象替代了<script>标签,然后 .script ()方法表示加载 Javascript 文件,不带参数的 .wait ()方法表示立即运行刚才加载的 Javascript 文件,带参数的 .wait ()方法也是立即运行刚才加载的 Javascript 文件,但是还运行参数中指定的函数。</p> <p> 这里需要注意的是,可以同时运行多条$LAB 链,但是它们之间是完全独立的,不存在次序关系。如果你要确保一个 Javascript 文件在另一个文件之后运行,你只能把它们写在同一个链操作之中。只有当某些脚本是完全无关的时候,你才应该考虑把它们分成不同的$LAB 链,表示它们之间不存在相关关系。</p> <p> 接下来是 requireJS 的改写:</p> <blockquote> <p><script src="require.js"></script></p> <p><script type="text/javascript"></p> <p>require ([</p> <p>"script1.js",<br /> "script2-a.js",<br /> "script2-b.js",<br /> "script3.js"</p> <p>],</p> <p>function (){</p> <p>initScript1 ();<br /> initScript2 ();<br /> initScript3 ();</p> <p>}</p> <p>);</p> <p></script></p> </blockquote> <p> require ()接受两个参数,第一个数组表示所要加载的 Javascript 文件,第二个是加载完成后所要运行的回调函数。原生的 require ()不支持按次序加载,所以四个 Javascript 文件到底先加载哪个,无法事前知道,require ()只保证这四个文件全部加载完成之后,才会运行所指定的回调函数。</p> <p> 如果按次序加载对你很重要,你可以使用官方提供的 <a href="/misc/goto?guid=4958192403141801370" target="_blank">order 插件</a>。<br /> <br /> 来自: <a id="link_source2" href="/misc/goto?guid=4958192403883060134" target="_blank">阮一峰的网络日志</a></p>