内容来源:http://hi.baidu.com/begin/item/df02bd79ca8cc0710d0a078a
按需加载js的研究和实现
加载js的基本原理,就是在DOM里面加载<script>元素,加载这些元素都是异步的过程。所以可以说是无阻塞的加载。
但是如果脚本之间存在依赖的话,就会出现不可预知的错误。根据这个,在加载脚本的时候,需要监听“load”事件,对于IE的特殊性,需要监听“readystatechange”事件。
基于这些,实现两个类,第一个类是,加载单个JS的加载器,第二个类,调用第一个类,实现加载多个js,并可配置,是否是同步加载(存在依赖)。
当然,根据传输方式的不同,可以使用Ajax的方式获取JS的内容,但是,Ajax存在跨域的问题,在此,没有采用。
实现代码如下:
ps. 实现了卸载脚本的方法,但是只能卸载DOM结构,无法实现JS的回收,也就是说浏览器依旧保留原先的脚本。
/*
*
usage:
var loader = new JsLoader()
loader.load("xxx.js");
loader.onsuccess =
function()
{
alert("loaded!");
}
*/
function
JsLoader()
{
this.load =
function(url)
{
this.url =
url;
//获取所有的<script>标记
var ss =
document.getElementsByTagName("script");
//判断指定的文件是否已经包含,如果已包含则触发onsuccess事件并返回
for (i = 0; i < ss.length; i++)
{
if (ss[i].src && ss[i].src.indexOf(url) != -1)
{
this.onsuccess();
return;
}
}
//创建script结点,并将其属性设为外联JavaScript文件
var s =
document.createElement("script");
s.type =
"text/javascript";
s.charset = "utf-8";
s.src = url;
//获取head结点,并将<script>插入到其中
var head =
document.getElementsByTagName("head")[0];
head.appendChild(s);
//获取自身的引用
var self =
this;
//对于IE浏览器,使用readystatechange事件判断是否载入成功
//对于其他浏览器,使用onload事件判断载入是否成功
s.onload = s.onreadystatechange =
function()
{
//在此函数中this指针指的是s结点对象,而不是JsLoader实例,
//所以必须用self来调用onsuccess事件,下同。
if (this.readyState && this.readyState == "loading")
return;
self.onsuccess();
}
s.onerror =
function()
{
head.removeChild(s);
self.onfailure();
}
};
//定义载入成功事件
this.onsuccess =
function()
{
};
//定义失败事件
this.onfailure =
function()
{
};
//卸载脚本
this.removejs =
function(filename)
{
if (!filename)
{
filename = this.url;
}
var allsuspects =
document.getElementsByTagName("script");
for (var i = allsuspects.length; i >= 0; i--)
{
if (allsuspects[i] && allsuspects[i].getAttribute("src") !=
null
&&
allsuspects[i].getAttribute("src").indexOf(filename) != -1)
allsuspects[i].parentNode.removeChild(allsuspects[i]); //remove
element by calling
parentNode.removeChild()
}
}
}
/*
*载入多个依赖脚本或不依赖的脚本
* usage:
* var loaders
= new JssProc();
*
loaders.loads(["xx.js","xx1.js"],true);//同步加载
*
loaders.loaded = function()
*
{
* alert("all loaded!");
* }
*/
function JssProc()
{
//是否同同步加载
this.loads = function(urls, isSyn)
{
var number =
0;
var self = this;
if (!isSyn)
{
for (var i = 0; i < urls.length; i++)
{
var s = new
JsLoader()
s.load(urls[i]);
s.onsuccess =
function()
{
number++;
if (number == urls.length)
{
self.loaded();
}
}
}
}
else
{
//递归方式
var j =
0;
function
load()
{
j++;
if (urls[j])
{
var ss = new
JsLoader();
ss.load(urls[j]);
ss.onsuccess =
load;
}
else
{
self.loaded();
}
}
var s = new
JsLoader();
s.load(urls[j]);
s.onsuccess = load;
}
}
//全部加载完调用的事件
this.loaded =
function()
{
}
//卸载多个脚本
/* * usage: var loader = new JsLoader() loader.load("xxx.js"); loader.onsuccess = function() { alert("loaded!"); } */ function JsLoader() { this.load = function(url) { this.url = url; //获取所有的<script>标记 var ss = document.getElementsByTagName("script"); //判断指定的文件是否已经包含,如果已包含则触发onsuccess事件并返回 for (i = 0; i < ss.length; i++) { if (ss[i].src && ss[i].src.indexOf(url) != -1) { this.onsuccess(); return; } } //创建script结点,并将其属性设为外联JavaScript文件 var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = url; //获取head结点,并将<script>插入到其中 var head = document.getElementsByTagName("head")[0]; head.appendChild(s); //获取自身的引用 var self = this; //对于IE浏览器,使用readystatechange事件判断是否载入成功 //对于其他浏览器,使用onload事件判断载入是否成功 s.onload = s.onreadystatechange = function() { //在此函数中this指针指的是s结点对象,而不是JsLoader实例, //所以必须用self来调用onsuccess事件,下同。 if (this.readyState && this.readyState == "loading") return; self.onsuccess(); } s.onerror = function() { head.removeChild(s); self.onfailure(); } }; //定义载入成功事件 this.onsuccess = function() { }; //定义失败事件 this.onfailure = function() { }; //卸载脚本 this.removejs = function(filename) { if (!filename) { filename = this.url; } var allsuspects = document.getElementsByTagName("script"); for (var i = allsuspects.length; i >= 0; i--) { if (allsuspects[i] && allsuspects[i].getAttribute("src") != null && allsuspects[i].getAttribute("src").indexOf(filename) != -1) allsuspects[i].parentNode.removeChild(allsuspects[i]); //remove element by calling parentNode.removeChild() } } } /* *载入多个依赖脚本或不依赖的脚本 * usage: * var loaders = new JssProc(); * loaders.loads(["xx.js","xx1.js"],true);//同步加载 * loaders.loaded = function() * { * alert("all loaded!"); * } */ function JssProc() { //是否同同步加载 this.loads = function(urls, isSyn) { var number = 0; var self = this; if (!isSyn) { for (var i = 0; i < urls.length; i++) { var s = new JsLoader() s.load(urls[i]); s.onsuccess = function() { number++; if (number == urls.length) { self.loaded(); } } } } else { //递归方式 var j = 0; function load() { j++; if (urls[j]) { var ss = new JsLoader(); ss.load(urls[j]); ss.onsuccess = load; } else { self.loaded(); } } var s = new JsLoader(); s.load(urls[j]); s.onsuccess = load; } } //全部加载完调用的事件 this.loaded = function() { } //卸载多个脚本 this.unload = function() { for (var i = 0; i < urls.length; i++) { new JsLoader().removejs(urls[j]); } }
this.unload = function()
{
for (var i = 0; i
< urls.length; i++)
{
new
JsLoader().removejs(urls[j]);
}
}
推介的网址:http://www.w3cfuns.com/article-1116-1.html