- 浏览: 1432265 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
1.预加载图片
图片除了可以用创建 img dom 节点的方法加载外,还可以用常见的缓存图片方法,Image对象加载,基本上创建出来的img dom node 和 new Image 对象 一样的,(除了没有实体标签不可以显示出来) ,但是 ie 对于从缓存中加载的图片触发事件有区别 (和事件添加位置有区别) ,详见代码。特别注意判断缓存加载,有的浏览器(ie chrome)缓存不触发load事件,应该判断img.complete。
2.动态加载 script
script 不像图片有专有的 javascript 对象,只能通过创建标签的方式加载script,但是 ie 和其他浏览器有区别,其他浏览器可以判断 load 事件 ,像图片一样,而 ie 不会触发这个事件,只能通过判断 readystate 的方式 来解决。
ps:
动态创建标签时,firefox当设置src时并不会立即开始下载脚本,只有将脚本标签 append 到 document 时,才开始下载,而image则在img src设置后立即开始下载,即使还没有被 append 到 document。
ie 浏览器判断 onreadystatechange 比较怪异,loaded 和 complete 每个并不确定出现,所以最好两者都判断,但为了防止执行逻辑两次,脚本加载后将 onreadystatechange 置空为好 ,如:
function loadScript(url, callback){ var script = document.createElement("script") script.type = "text/javascript"; if (script.readyState){ //IE script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function(){ callback(); }; } script.src = url; document.body.appendChild(script); }
updated : 2011-05-11
在 ie6,7,8 下有缓存情况,嵌套的动态加载会出问题
loadScript("right.js",function(){ loadScript("right2.js",function(){alert(2);}); });
则 alert(2) 也不会执行!
举个例子From Even Faster Websites :
Coupling Asynchronous Scripts ,若一段inline脚本依赖于一个外部脚本文件,而我们用script dom 添加的方式载入外部脚本,因为除了firefox 都不能保证等外部脚本加载完毕再执行内部脚本,所以的采用其他方法。
1.判断script 状态
var aExamples = [['couple-normal.php', 'Normal Script Src'],...]; function init() { //依赖于menu.js EFWS.Menu.createMenu('examplesbtn', aExamples); } var domscript = document.createElement('script'); domscript.src = "menu.js"; //opera 会 load 两次,so 设置变量 domscript.onloadDone = false; //标准方式 domscript.onload = function() { domscript.onloadDone = true; init(); }; //ie 和 opera ? domscript.onreadystatechange = function() { if ( "loaded" === domscript.readyState && ! domscript.onloadDone ) { domscript.onloadDone = true; init(); } } document.getElementsByTagName('head')[0].appendChild(domscript);
2.Degrading Script Tags
ejohn 在他的blog中提出了这个优雅而又怪异的方法 ,关键要在外部脚本后加入代码执行外部脚本的 innerHTML
如上述的 menu.js,最后添加
var scripts = document.getElementsByTagName("script"); var cntr = scripts.length; while ( cntr ) { var curScript = scripts[cntr-1]; //如果找到它自己 if ( -1 != curScript.src.indexOf("menu.js") ) { //执行依赖它的内部脚本 eval( curScript.innerHTML ); break; } cntr--; }
使用 menu.js 的代码 :
<script type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'],...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } var domscript = document.createElement('script'); domscript.src = "menu.js"; //设置依赖的要执行的代码 if ( -1 != navigator.userAgent.indexOf("Opera") ) { domscript.innerHTML = "init();"; } else { domscript.text = "init();"; } document.getElementsByTagName('head')[0].appendChild(domscript); </script>
3.其他方法:
比如 setTimeout polling,外部脚本硬编码callback,window.onload 再执行内部脚本,都不如上述两个方法。
注意: 异步新载入的script标签即使后来删除掉,其里面定义的函数,变量仍然存在于window 中,所以请不要将这种方式滥用,建议只用于跨域的数据交换 。
2.1 script 加载完毕的另一种判断,反向通知
2009-07-03 修正
但是 script 和 img不同的是,异步载入的javascript可以反向通知调用方,即调用调用方的代码告知自己已经载入完毕。
如 Ext.data.ScriptTagProxy
这就需要异步载入的javascript要调用调用方提供的临时的一个全局函数,调用完毕将这个全局函数删除。
如 ScriptTagProxy :
window[trans.cb] = undefined; try{ delete window[trans.cb]; }catch(e){}
每次请求都临时产生一个全局函数window[trans.cb]来等待异步载入的javascript来执行。
注意:
try{
delete window[trans.cb];
}catch(e){}
由于
IE不能清除window上的属性,会抛出无法操作的异常
,这里捕捉一下,我认为不清除也无所谓,设成 undefined 就可以垃圾回收了呀。
ps:关于delete的详细解释 :Understanding delete
2.2 关于 window 属性清除问题还要注意:
如果不是显式设置 window.property,那么property ie ff都无法清除,但是ff不会报错的。如:
var test=function (){ alert(1); }; /*或者 function test(){ alert(1); }; */ delete window["test"]; delete test; alert(window["test"]);
2.3 多个异步脚本加载顺序问题
通过同时动态创建多个脚本节点来异步加载脚本,ie与firefox之间也有差异,ie只要节点src设置即可开始下载,firefox则要将节点插入到文档才开始下载,虽然它们都会同时开始下载,但是完成的通知时间不同,firefox的通知时间与插入文档的顺序相同
(注:firefox 3.6 script引入async属性 ,默认为false,若设为true则和ie表现一致,firefox 4.0 起参数默认 true )
,而ie则哪个先下载完先通知哪个:(可使用fiddler模拟拨号上网测试)
<script type="text/javascript" src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script> <script> YUI({ filter: "DEBUG" }).use("*", function (Y) { var script1 = document.createElement("script"); script1.setAttribute("src", "http://yui.yahooapis.com/combo?3.1.0/build/oop/oop-min.js&3.1.0/build/dom/dom-min.js&3.1.0/build/pluginhost/pluginhost-min.js&3.1.0/build/event-custom/event-custom-min.js&3.1.0/build/node/node-min.js&3.1.0/build/event/event-min.js&3.1.0/build/attribute/attribute-base-min.js&3.1.0/build/base/base-min.js&"); console.log(script1.async); //script1.async=true; document.getElementsByTagName("head")[0].appendChild(script1); script1.onload = function () { console.log("script1 load"); }; script1.onreadystatechange = function () { var rs = this.readyState; if ("loaded" === rs || "complete" === rs) { // Y.log(id + " onreadstatechange " + url, "info", "get"); script1.onreadystatechange = null; console.log("script1 onreadystatechange"); } }; var script2 = document.createElement("script"); script2.setAttribute("src", "http://yui.yahooapis.com/combo?3.1.0/build/dom/dom-min.js"); document.getElementsByTagName("head")[0].appendChild(script2); script2.onload = function () { console.log("script2 load"); }; script2.onreadystatechange = function () { var rs = this.readyState; if ("loaded" === rs || "complete" === rs) { // Y.log(id + " onreadstatechange " + url, "info", "get"); script2.onreadystatechange = null; console.log("script2 onreadystatechange"); } }; }); </script>
PS : defer 和 async 作用并不一样,图解:
http://msdn.microsoft.com/en-us/library/ms533719%28VS.85%29.aspx
https://developer.mozilla.org/En/HTML/Element/Script
http://www.w3.org/TR/html5/scripting-1.html#script
2.4 动态添加脚本的同步与异步问题
当动态添加脚本时,不同的应用场景可能需要不同的脚本处理顺序,注意:当动态添加内联脚本时为同步,添加外部脚本时为异步:
同步:
var script1 = document.createElement("script"); document.getElementsByTagName("head")[0].appendChild(script1); script1.text="alert('script1 loaded');"; alert(1);
输出:script1 loaded 1
异步:
var script2 = document.createElement("script"); script2.setAttribute("src", "test.js"); document.getElementsByTagName("head")[0].appendChild(script2); script2.onload = function () { alert("script2 load"); }; script2.onreadystatechange = function () { var rs = this.readyState; if ("loaded" === rs || "complete" === rs) { // Y.log(id + " onreadstatechange " + url, "info", "get"); script2.onreadystatechange = null; alert("script2 load"); } }; alert(2);
输出:2 test.js loaded script2 loaded
test.js:
alert("test.js loaded");
2.5 出错判断
2011-03-03 note :
当动态加载的脚本发生错误(比如服务器返回 404 )时,ie和标准浏览器(firefox,chrome)表现也有区别:
1. ie 在 404 情况下仍然会使得脚本的 readyState 变为 loaded 或者 complete,所以如果想知道是否出错,估计得修改业务逻辑 。
2. firefox,chrome 在服务器出错时会触发 error 事件,通过监听 error 以及 load 可立即知道成功与否。
总体测试代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>XXX</title> <script src="ext-base.js" type="text/javascript"></script> <script src="ext-core.js" type="text/javascript"></script> </head> <body> <input type="button" value="load image" id="test" /> <input type="button" value="load script" id="test2" /> <script type="text/javascript"> Ext.DomHelper.useDom = true; Ext.onReady(function () { Ext.get('test2').on('click', function (evt) { //即使移除script标签,函数依旧在内存中存在 if (Ext.get('st')) Ext.get('st').remove(); //so assign to undefined explicitly window['writeflashhtml'] = undefined; //sorry can not delete 在window声明的函数 //delete window['writeflashhtml']; //alert(typeof window['writeflashhtml']); var el = Ext.DomHelper.append(Ext.getBody(), { tag: 'script', id: 'st' //, //src:"http://img.12580zgz.com/js/flashobj.js" }, true); el.dom.src = "http://img.12580zgz.com/js/flashobj.js"; /* ie 不会触发load 事件,ie 以外浏览器 会 */ el.on('load', function () { alert("non-ie createElement onload:" + writeflashhtml); }); /* ie 这样判断是否加载完毕 */ el.dom.onreadystatechange = function () { if ( //this.readyState == 4 this.readyState == 'complete' || this.readyState == 'loaded') { alert(this.readyState + " : ie createElement onload:" + writeflashhtml); } el.dom.onreadystatechange = null; }; evt.stopEvent(); }); Ext.get('test').on('click', function (evt) { var im = new Image(); /* 将onload 移到前面 ,ie 则每次都会触发onload 事件 im.onload=function(){ alert("new Image load:"+this.width); } */ im.src = "http://img.12580zgz.com/images/logo-w3c.gif"; /* 将onload 放在后面,则 ie取缓存图片时不会触发onload事件*/ // im.addListener("load",function(){}); im.onload = function () { alert("new Image load:" + this.width); } //图片来自缓存触发,或者到这已经图片载入,所有浏览器使用 if (im.complete) { alert("new Image complete:" + im.width); } var el = Ext.DomHelper.append(Ext.getBody(), { tag: 'img' }, true); /* 将onload 移到前面 ,ie 则每次都会触发onload 事件 el.on('load',function(){ alert("createElement onload:"+this.dom.width); }); */ el.dom.src = "http://img.12580zgz.com/images/logo-w3c.gif"; /* 将onload 放在后面,则 ie取缓存图片时不会触发onload事件*/ el.on('load', function () { alert("createElement onload:" + this.dom.width); }); //来自缓存触发,或者到这已经图片载入,所有浏览器使用 if (el.dom.complete) { alert("createElement complete:" + el.dom.width); } evt.stopEvent(); }); }); </script> </body> </html>
ps: Iframe与窗口文档 相关操作
javascript 与 iframe
页面加载判断与onload 研究
参考文章:
Loading JavaScript without blocking
评论
function loadJS (url, onload) {
var domscript = document.createElement('script');
domscript.src = url;
if ( onload ) {
domscript.onload = onload;
domscript.onreadystatechange = function() {alert(life_assist);
if (domscript.readyState == "loaded"||domscript.readyState == "complete" ) {
domscript.onload();
}
}
}
document.getElementsByTagName('head')[0].appendChild(domscript);
}
/*********************动态载入JS Satrt************************/
/*******绑定到window.onload且不覆盖已有方法 Start*************/
if (document.all) {
window.attachEvent('onload', bodyloadready);
}
else {
window.addEventListener('load', bodyloadready, false);
}
/*******绑定到window.onload且不覆盖已有方法 Start*************/
function bodyloadready(){
loadJS('htdocs/js/life_assist.js',function (){
alert(1);
});
};
发表评论
-
continuation, cps
2013-09-12 16:49 2712起 随着 nodejs 的兴起,异步编程成为一种潮流 ... -
一种基于匹配回朔的 css3 选择器引擎实现
2013-05-07 20:40 3344一种基于匹配回朔的 css3 选择器引擎实现 介绍 C ... -
cubic-bezier 模拟实现
2013-01-05 16:34 14012cubic-bezier 曲线是 css3 动画的一个重要基石 ... -
构建前端 DSL
2012-10-11 22:10 5282目前在传统的软件开 ... -
Get cursor position and coordinates from textarea
2012-04-10 20:50 4923最近需要从 textarea 中获 ... -
兼容 ie 的 transform
2012-02-23 14:00 6331css 2d transform 是 css3 引入的一个新的 ... -
promise api 与应用场景
2012-02-07 17:34 7280promise 是 commonjs 社区中提出的异步规范,其 ... -
closure compiler 代码优化实例
2012-01-08 03:23 2766closure compiler 可以进行不少有意思的优化 ... -
write html parser
2011-12-01 02:48 2845首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取 ... -
获取剪贴板数据
2011-11-07 23:31 6374兼容性: 获取剪贴板数据这块各个浏览器间存在很大的 ... -
url 映射问题
2011-11-07 21:52 3160背景 url mapping 我最早知道是作为 j ... -
tip:如何原生播放声音
2011-10-19 12:45 2890如果不想考虑浏览器间 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2784简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2785场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2198分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 6931作为前端开放的基础安全保证,caja 是目前比较合 ... -
tokenization of html
2011-08-29 22:38 2672html 符号解析问题 场景: 在页面上输出包 ... -
ie 下 cloneNode 导致的属性克隆
2011-08-24 16:10 2409这个还是很值得记下,一直存在的很大隐患终于解决,由于在 ie& ... -
循环引用下的深度克隆
2011-08-04 20:39 2229深度复制和浅度复制 是当初初学 c 遇到的第一批问题,似乎使 ... -
模块的静态与动态循环依赖
2011-07-25 03:43 3189场景: 循环依赖 我是不支持的,但现实中似乎又确实需 ...
相关推荐
当项目js(css)文件使用越来越多,js 文件的加载也成了性能上的一个问题,此资源能够在页面全部加载完成后异步加载js等资源文件,它可以顺序加载资源列表,也可以并发加载资源列表,它包含一个方法调用接口:...
异步加载全攻略,包括:thread加载、asyncTask加载、lruCache等
基于Unity封装的AB包资源管理器,实现同步加载/异步加载AB包以及依赖包,详细可以到我的博客查看文章,里面也有完整代码。
这个是一款 Unity3D异步加载场景资源 ,界面简洁漂亮的加载画面,内含多个样式,提供给广大的Unity3D学者研究。
JS异步加载图片
资源异步加载的一个Request脚本
异步加载网络资源并分页显示在ListView中
unity通过协程实现异步下载数据并加载
Unity3D 场景加载过渡资源 异步加载场景资源 附带自然的加载画面 公司项目demo 亲测好用 软件载入中界面 pc和安卓都支持
综合网上资源制作的,根据那些零碎的代码组合的,高手请跳过。已经整理好,可以运行。(特别注意,只有第一个根目录树加载了右键命令,第二个没有加载,自己可以根据需要改变每个树的右键命令)
本项目是根据慕课网《android必学-异步加载》视频教学所开发的一套异步加载网络资源的小demo.其中分别用到了多线程、AsyncTask实现异步加载的功能。 里面还包括了: json解析、网络请求、LruCache缓存、滚动优化等...
一款详解U3D协同函数与异步加载的实战视屏,适合新手学习!
Android平台的图像控件,可以异步加载网络图片、项目资源和本地图片,并且支持双指缩放、图片的基本处理 Android平台的图像控件,可以异步加载网络图片、项目资源和本地图片,并且支持双指缩放、图片的基本处理 ...
vue.router异步加载资源
使用Android Studio打开即可
Yepnope.js是一个能够根据输入条件来选择性异步加载资源文件的js脚本,可以在页面上仅加载用户需要的js/css。 示例代码: yepnope([ { test : Modernizr.indexeddb, yep : ['/js/indexeddb-wrapper.js', '/css/...
介绍Unity3D的资源异步加载与显示进度条
项目中摘抄出来的代码,在LoadingLayer::onEnter()中,开了一个boost thread来加载资源