js 外部文件加载处理
概述
前端在日常工作中很大一部分时间是在思考页面的优化方案,让页面载入得更快。鉴于javascript是单线程的事件驱动语言,优化工作之一就是:控制图片、swf、iframe等大流量文件以及js和css等文件的加载顺序,让它们井然有序的进入到页面中,页面就能尽可能完整的呈现在他们眼前。而为了更好的用户体验,我们要知道每个文件触发onload事件的方案,因为它们在各个浏览器中的表现不尽相同。
iframe的 load 事件
在所有为IFRAME动态添加onload监听事件的方法中,只有 使用事件监听方式为 IFRAME 的 onload 事件绑定处理函数,IE6、7、8才有效。所以为 IFRAME 添加load事件完美方案如下:
// 事件监听兼容方案
function addEvent(elem,event,fn){
if (elem.attachEvent) {
elem.attachEvent('on'+event,fn)
} else {
elem.addEventListener(event,fn,false)
}
} window.onload = function(){
var iframeA = document.createElement('iframe');
iframeA.src = 'http://www.baidu.com'
addEvent(iframeA,'load',function(){
document.body.bgColor = '#000'; // 回调函数
});
document.body.appendChild(iframeA);
}
优化页面建议不要嵌套iframe,但是在内部项目还是很常见。其实在IE中,监控iframe加载完毕还可以采取监听 onreadystatechange 事件。
flash 的 load 事件
解决flash的 load主要是两个问题:获取flash对象和flash何时加载完毕。
首先第一个问题:如果object和embed用同样的ID,获取flash对象的时候,IE会认不出。解决方案:
- js判断IE和非IE,IE中是object,非IE中是embed。
- 通过flash对象的PercentLoaded方法,检测其值是否为100。
html代码
<div id="load">flash加载中....</div>
<div id="swfWrap"></div>
css代码
#swfWrap{width:200px;height:200px;}
#load{width:200px;color:#fff;text-align:center;background-color:#eee;}
js代码
// 封装通过ID获取
function $(id){
return document.getElementById(id)
} var isIE = navigator.appVersion.indexOf("MSIE") != -1 ? true: false; // 监听flash是否加载成功
function listenMovie(flash){
try{
return Math.floor(flash.PercentLoaded()) == 100 ;
}catch(e){
return false;
}
} // 获取FLASH对象
function thisMovie(movieName) {
if (isIE) {
return window[movieName];
}
else {
return document[movieName];
}
} // 创建flash
function createFlash(id,url){
var html = '<object id="flash" height="200" width="200" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">'+
'<PARAM NAME="FlashVars" VALUE="">'+
'<PARAM NAME="Movie" VALUE="'+url+'">'+
'<PARAM NAME="WMode" VALUE="Transparent">'+
'<PARAM NAME="Quality" VALUE="High">'+
'<PARAM NAME="AllowScriptAccess" VALUE="always">'+
'<embed type="application/x-shockwave-flash" src="'+url+'" id="flashFF" name="flashFF" wmode="window" quality="high" width="200" height="200"></embed>'+
'</object>';
$(id).innerHTML = html;
} window.onload = function(){
createFlash('swfWrap','flips2.swf')
var flashObj = isIE ? thisMovie("flash") : thisMovie("flashFF");
var intervalID = setInterval(function(){
if (listenMovie(flashObj)) {
clearInterval(intervalID);
intervalID = null;
$('load').innerHTML = 'flash加载完毕';
}
},60)
}
其中object中的 classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 不能去掉,不然IE6下会获取取不到flash对象;embed的name值也不能去掉,不然chrome也获取不到。
这里再提下flash的通信的问题,可以参考 这里,解决方法就是将EMBED的 swliveconnect 属性设置成true,然后就可以跟flash通信了。
IMG的 load 事件
img的load事件,我们使用 new Image()。这里我们得注意 complete 事件。研究网上的得出以下代码:
var img = new Image();
img.src= "http://i1.hoopchina.com.cn/user/627/17191627/17191627_big_3.jpg";
if (img.complete || img.width) {
alert("该图片已经在缓存中,不需要再下载")
alert(img.height)
} else {
img.onload = function() {
alert("图片加载完成");
alert(img.height)
}
}
这里网上很多说法是这样子说的,只要加载过一次图片,img.complete就变成true了,图片就存进浏览器缓存,下次再加载就直接忽略了onload事件,直接从缓存里去读取,而不是再重新去下载。但是我在多个变化条件下(同一个浏览器、同一个标签页、清楚缓存、一个页面存在多个相同图片)测试发现:
在f5刷新后,除了火狐是直接从缓存中读取的,也就是执行 if(img.complete || img.width)语句下的,其他的浏览器都是执行else语句里的代码,重新下载图片;ctrl+f5的话,则所有浏览器都是重新下载图片的。
那么 img.complete 的真正意义在于什么呢?一张页面中,如果存在多个图片地址相同的 img 标签 ,浏览器只会请求一次图片链接,而不是每个img都去请求。
使用 new Image() 请求相同的 gif 图片时,img.complete 貌似不准确,不知道什么原因,难道是因为 gif 动态图是由多张静态图组成?。
而网上说的,将src赋值放在onload事件之后,并不是从根本原因上解决问题。
JS的 load 事件
首先准备一下即将要用到的辅助函数:
function delay_file(url) {
var type = url.split('.'),
file = type[type.length - 1];
if (file == 'css') {
var obj = document.createElement('link'),
lnk = 'href',
tp = 'text/css';
obj.setAttribute('rel', 'stylesheet');
} else {
var obj = document.createElement('script'),
lnk = 'src',
tp = 'text/javascript';
}
obj.setAttribute(lnk, url);
obj.setAttribute('type', tp);
file == 'css' ? document.getElementsByTagName('head')[0].appendChild(obj) : document.body.appendChild(obj);
return obj;
};
考虑到js加载的特殊性,浏览器引擎在解析js时,对其他资源和文档都会停止。所以我们采用以上方法来异步加载js。而如果想给它增加 回调函数 呢?非IE下 onload 是完美支持的,IE下我们则用 onreadystatechange 事件监听 readyState 值变化。
function loadjs(url, callback) {
var elem = delay_file(url);
var isIE = navigator.userAgent.indexOf('MSIE') == -1 ? false : true;
if ( isIE ) {
elem.onreadystatechange = function() {
if (this.readyState && this.readyState == 'loading') return;
if (callback) {
callback();
}
};
} else {
elem.onload = function() {
if (callback) {
callback();
}
};
}
}
CSS的 load 事件
CSS 的load事件跟以上讲的 onload 事件兼容性却是相反的,其他浏览器不支持 load 事件,在IE浏览器中反而是支持的。那怎么办呢?
seajs给出了一个方案:
function loadcss(url, callback) {
var elem = delay_file(url);
if (elem.attachEvent) {
elem.attachEvent('onload', callback);
} else {
setTimeout(function() {
poll(elem, callback);
}, 0);
}
function poll(_elem, callback) {
var isLoaded = false;
var sheet = _elem['sheet'];
var isOldWebKit = (navigator.userAgent.replace(/.*AppleWebKit\/(\d+)\..*/, '$1')) * 1 < 536;
if (isOldWebKit) { //webkit 版本小于 536
if (sheet) {
isLoaded = true;
}
} else if (sheet) {
try {
if (sheet.cssRules) {
isLoaded = true;
}
} catch (ex) {
if (ex.code === 'NS_ERROR_DOM_SECURITY_ERR') {
isLoaded = true;
}
}
}
if (isLoaded) {
setTimeout(function() {
callback();
}, 1);
} else {
setTimeout(function() {
poll(_elem, callback);
}, 1);
}
}
}
貌似linkNode在加载前后 linkNode.sheet 和 linkNode.sheet.cssRules 的值会发生变化。我觉得还有一个方法虽然有点绕,但是也是最有效的方法:检测某个类名下的CSS属性是否存。
js 外部文件加载处理的更多相关文章
- 在IIS上新发布的网站,样式与js资源文件加载不到(资源文件和网页同一个域名下)
在IIS上新发布的网站,网站能打开,但样式与js资源文件加载不到(资源文件和网页是同一个域名下,例如:网页www.xxx.com/index.aspx,图片www.xxx.com/pic.png). ...
- Three.js外部模型加载
1. 首先我们要在官网: https://threejs.org/ 下载我们three.js压缩包,并将其中的build文件夹下的three.js通过script标签对的src属性导入到我们的页面中 ...
- 关于html,css,js三者的加载顺序问题
<head lang="en"> <meta charset="utf-8"> <title></title> ...
- html文件在head标签中引入js地址和直接写js代码,所用时间是不同的,因为引入js地址,文件加载的时候需要通过通讯协议去解析地址,读取外部文件
html文件在head标签中引入js地址和直接写js代码,所用时间是不同的,因为引入js地址,文件加载的时候需要通过通讯协议去解析地址,读取外部文件
- 前端设计中关于外部js文件加载的速度优化
在一般情况下,许多人都是将<script>写在了<head>标签中,而许多浏览器都是使用单一的线程来加载js文件的,从上往下,从左往右. 若是加载过程出错,那么网页就会阻塞,就 ...
- js文件加载优化
在js引擎部分,我们可以了解到,当渲染引擎解析到script标签时,会将控制权给JS引擎,如果script加载的是外部资源,则需要等待下载完后才能执行. 所以,在这里,我们可以对其进行很多优化工作. ...
- js怎么动态加载js文件(JavaScript性能优化篇)
下面介绍一种JS代码优化的一个小技巧,通过动态加载引入js外部文件来提高网页加载速度 [基本优化] 将所有需要的<script>标签都放在</body>之前,确保脚本执行之前完 ...
- WebGL three.js学习笔记 加载外部模型以及Tween.js动画
WebGL three.js学习笔记 加载外部模型以及Tween.js动画 本文的程序实现了加载外部stl格式的模型,以及学习了如何把加载的模型变为一个粒子系统,并使用Tween.js对该粒子系统进行 ...
- Android应用安全之外部动态加载DEX文件风险
1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...
随机推荐
- php 判断数组相等 数组运算符介绍
如何判断两个数组相等呢?其实很简单,用 == 或者 === 就可以了 php手册里说明如下, 例子 名称 结果 $a + $b 联合 $a 和 $b 的联合. $a == $b 相等 如果 $a 和 ...
- docker 镜像和容器的批量清理
镜像和容器的清理 删除所有运行中的容器 $ docker kill $(docker ps -q) 删除所有停止的容器 $ docker rm $(docker ps -a -q) 删除所有没有tag ...
- hdoj Last non-zero Digit in N! 【数论】
找规律! 求N!最后非0位的值.比方2是120的最后一个不是0的值. 输入N比較大,要大数保存. 注意到最后0的个数是与5的因数的个数相等.设f(n)为n!的最后非0位. 那么f(n)=((n%5)! ...
- CentOS+Nginx+PHP+MySQL详细配置(图解)
原文地址: http://www.jb51.net/article/26597.htm CentOS+Nginx+PHP+MySQL详细配置(带有图解),需要的朋友可以参考下. 一.安装MySQL ...
- 最近的两个小项目,1:在Vscode里写C/C++
时间过得真快,一眨眼一个多月没更新了,但这一个月我可没偷懒啊,真的是忙.粘上两篇ReadMe勉强凑合一下,保持博客更新是好习惯. VscodeCppDemo Try to develop C/C++ ...
- 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O
Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...
- CSS定位:相对定位、绝对定位和固定定位(relative absolute fixed)
相对定位:position:relative; 不脱离文档流,参考自身静态位置通过top,bottom,left,right定位,并且可通过z-index进行层次分级. 绝对定位:position:a ...
- 45种Javascript技巧大全
JavaScript是一个绝冠全球的编程语言,可用于Web开发.移动应用开发(PhoneGap.Appcelerator).服务器端开发(Node.js和Wakanda)等等.JavaScript还是 ...
- ubuntu JDK
第一步:下载jdk-7-linux-i586.tar.gz 第二步:解压安装 cd /usr/libsudo mkdir jvm cd {你的目录jdk压缩文件目录} sudo tar zxvf jd ...
- 在Mac OS上搭建本地服务器
我们在做网络编程的时候一般是需要有网络环境的,这样可以边写边测试达到很高的效率.但有些时候我们由于很多原因我们的电脑无法连接到网络,这时就会感觉很不自在,所以今天在这里教大家怎么用自己电脑作服务器. ...