Lazyload实践口碑网吴天豪
Introduce 吴天豪口碑网-UED-前端开发工程师大三爱折腾博客: www.f2es.com
关于交流会主动分享分享没有大小一个困扰你很久的问题一个五分钟的小发现一个好的提高开发效率的工具一份好的开发经验
Lazyload直译:惰性加载一般我们都会叫它做“延迟加载”http://en.wikipedia.org/wiki/Lazy_loading
http://docs.kissyui.com/kissy/docs/datalazyload/index.htmlhttp://www.appelsiini.net/projects/lazyloadhttp://developer.yahoo.com/yui/imageloader/
Why lazyloadStart soonerStop waiting
一般我们会用于加载js加载html块
延迟加载jshttp://book.douban.com/subject/5362856/http://book.douban.com/subject/4719162/
Total_Speed = Time_to_Download + Time_to_parse + Time_to_execute(evaluation)
Js-其实是一个老话题了为什么要延迟加载js当浏览器下载执行js时,页面的下载和渲染处于等待状态为什么停滞?大家思考一下1.当页面一边渲染html和css,一边下载并执行脚本,what will happen?脚本操作的元素可能根本就还没有渲染出来
如果我们的脚本放在页面的顶部,比如head里面,或者把脚本在页面中间,页面会等待脚本下载和执行这在页面生存周期中是必要的,因为脚本执行过程中可能会修改页面内容
组织脚本脚本放到页面底部合并URL (minify)因为http请求会带来额外的性能消耗,因此下载单个100k的文件比下载4个25k的文件要快。无阻塞的脚本异步加载js文件
动态加载脚本方式:XHR动态脚本DeferAsync…….
文件之间的依赖关系执行顺序并行下载
介绍一个比较少见的方式Script in iframe页面中的iframe和其他元素是并行加载的,这样就可以无阻塞的加载script脚本存在跨域问题
动态脚本能很好的处理脚本之间的依赖关系
监听js是否加载并准备就绪Firefox,Opera,Chrome,Safari 3+script.onloadiescript.readystatechangescript.readyState  === “loaded”  script.readyState === “complete”
LoadScript(“jQuery.js”, function(){	$(function(){		//jQuery code	}; }
不过…文件一多…loadScript(“a.js”, function(){loadScript(“b.js”, function(){loadScript(“c.js”, function(){loadScript(“d.js”, function(){				alert(“哎呀我擦,终于加载好了”);			}		}	}}
这样看起来就舒服多了Load([“a.js”, “b.js”, “c.js”, “d.js”] , function(){	//do something });
这样就更好了Load(“d.js”, function(){	//do something})“d.js” 依赖于[“a.js”, “b.js”, “c.js”]
豆瓣dohttp://site.douban.com/widget/notes/22456/note/87598595/
n.onload = n.onreadystatechange = function () {    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {        _loaded[this.getAttribute('src')] = true;        if (cb) {cb(this.getAttribute('src'), context);        }        //防止ie6的内存泄漏问题n.onload = n.onreadystatechange = null;    }};
加载单个文件的处理。接受五个参数:url, type(文件类型), charset(编码), cb(要对应执行的方法), context(执行上下文环境)
Do.add('common', {path: 'http://img3.douban.com/js/site/packed_common0.js', type: 'js'});Do.add('common-eventhandler', {path: 'http://img3.douban.com/js/site/packed_common_eventhandler0.js', type: 'js', requires: ['common']});Do('common', 'common-eventhandler');
问题依然存在:下载a.js -> 执行a.js回调 -> 下载b.js -> 执行b.js的回调-> 下载c.js -> 执行c.js的回调-> 下载d.js -> 执行d.js的回调不能做到并行下载….
在chrome和safari里,通过动态script加载的脚本并不会按照插入的顺序执行,而是哪个先加载好哪个执行That’s pretty bad!
那么在chrome/safari里,可以插入一个<script type=“text/cache” src=“#”>来实现,type=“text/cache”的脚本下载好后会缓存并触发onload,但不会执行。之后再插入script type=“text/javascript”,因为这个时候脚本都已经下载好,所以插入的顺序就是执行的顺序了
多一次插入就多浪费一次资源使用这个方法实属无奈
最后,统一的解决方案同域文件用xmlhttprequest请求过来这时,脚本是以字符串的形式传递过来的var s = document.createElement('script'); s.text = xhrObj.responseText;head.appendChild(s);
这种方法避开了evil eval,并且和DOM Script一样,可以按顺序加载js文件,当然,不会阻塞后续资源的加载。更为重要的是,在所有浏览器下,这种方法都不会阻止渲染和onload事件,体现了XMLHTTPRequest异步请求的本色。
跨域的脚本Firefox/opera里可以用动态 Script DOM element ,完美地实现并行下载和顺序执行对于 Safari/Chrome/IE ,无法保证顺序执行,通过插入一个 <script type=“text/cache” src=“#”> 来实现。
defer和async的区别Defer 延迟Async异步
关于defer<script src=" " defer></script>加上 defer 等于在页面完全在入后再执行脚本,相当于 window.onload,但应用上比 window.onload更灵活告诉浏览器这段脚本不需要立即执行,从而做到异步加载,不阻塞其他资源下载在window.onload处理之前执行defer的脚本
Defer的水很深…http://msdn.microsoft.com/en-us/library/ms533719(VS.85).aspxhttps://developer.mozilla.org/En/HTML/Element/Script#attr-defer都没有涉及执行顺序的问题…
defer在ie下能保持执行顺序,无论哪个先下载好---《高性能网站建设进阶指南》35页测试结果很怪异…http://www.websiteoptimization.com/speed/tweak/defer/动态插入的脚本,即使设置defer,依然不能保证执行顺序
<head><script defer>  	 alert(3);</script><script> 	 alert(1);</script></head><body><script defer>  	 alert(4);</script><script> 	 alert(2);</script><script>window.onload = function(){  	  alert(5);  }</script></body>http://stevesouders.com/cuzillion/?ex=10017&title=IE+Ensure+Order+Excution
Html5 asyncThis Boolean attribute is set to indicate that the browser should, if possible, execute the script asynchronously. If the script cannot be executed asynchronously, or the browser doesn’t support this attribute, the script is executed synchronously (and loading the content blocks until the script finishes running).加了这个属性就意味这该脚本的执行不会影响页面的加载
区别
回到根源Reduce(减少文件大小)Defer(延迟)Go Async(异步)Be Lazy(懒加载)Bite Size(真的需要 JS 吗)
更好的了解script标签https://developer.mozilla.org/En/HTML/Element/Scripthttp://msdn.microsoft.com/en-us/library/ms535892(VS.85).aspx
Html lazyload对html片段进行延迟加载极大地减少页面渲染时间同时解决了图片加载的问题
实践Sina微博Twitter淘宝商城等等
思路1.正常渲染一屏多一点大小的页面2.把剩下的html代码放到一个容器中,这时不会解析,以文本的形式存在3.随着用户进行的页面滚动操作逐步渲染页面4.为开发人员提供相应操作的接口
1.容器的选择textareanoscript你会选择哪个?
容器要求内部的元素全部以文本或者文本节点的形式解析可以可判断位置访问内部的文本
Textarea应用:淘宝商城其实,挺好,貌似没有什么大问题,我们需要的基本功能都已经实现了
noscript在开启脚本的情况下,元素本身可以获取,但是不含占位属性,比如offsetTop,offsetLeft,或者height,width之类的在IE789下,内部的文本节点是不可访问的或者说在浏览器在开启脚本的情况下渲染好之后就把内部的文本删除了,No dom, no data
看起来textarea对noscript有着压倒性的优势
是么?
你希望那些不开启脚本的用户就没法使用你的产品了么?
在口碑网上一次调查时,不开启脚本的访问用户占0.5%到1%,不是一个小数目
页面的优化和可用性不应该是两个不同的走向
noscript解决方案对于noscript的占位属性丢失获取到noscript元素,并在外层套一个textarea元素,textarea元素用visibility:hidden隐藏为什么不用display:none?之后,判断noscript元素是否在视口内的任务就顺利移交给了textarea为什么不用别的元素?比如div之类的这里就涉及到了文本转义的问题
noscript解决方案对于IE789对noscript内部元素的处理感谢stackoverflow,有位老兄也在研究这个问题使用iframe来引入noscript元素,然后用ajax动态请求iframe的html代码,因为这部分代码实际上已经在用户浏览的页面上了拿到完整的html之后用正则把每个noscript内部的文本切割到一个数组里
<iframe class="k2-display-none" src="?noscript=true"></iframe>我们可以这样发一个请求Y.io("?noscript=true", cfg);o.responseText就是含有当前页面noscript标签的html字符串
坚持noscript为了提高页面的可访问性
还有问题开发人员的脚本和一些元素有依赖关系如果元素没有加载就执行脚本会导致脚本报错让开发人员在每次获取元素之前都先判断元素是否存在不靠谱,并且脚本并不能直接知道元素到底加载好了米
把脚本的初始化放到对应的html块里?好处,脚本会随着元素的加载执行好吧,这让页面的维护变的非常困难,脚本东一段西一段的
自定义事件我们创建一个自定义事件,这个事件的目的就是在某个html块加载好的时候发出一个广播,让脚本知道所要操作的元素已经加载好。脚本绑定这个事件。
自定义事件Y. publish(evt_type, opts)在Y.EventTarget. _yuievt.events里存储Y. fire( evt_type )触发绑定的回调事件队列
再具体一点添加自定义事件Y.pulish("lazyloadReady:" + i, {          type : "lazyloadReady:" + i,          preventable : false});
触发事件ev = "lazyloadReady:" + (i + 1);Y.fire(ev);
绑定事件Y.on("lazyloadReady:1" , function(){     alert("第一个模块加载完成");});暂时使用了页面上noscript标签的序号作为事件名…还在考虑更好的方法
创建iframe元素带来的开销是其他元素的1~2数量级频繁的字符串操作,性能上有待提高…
看看kissy怎么做的dataLazyload.addCallback(el, fn) 表示当 el 即将出现时,触发 fn具体实现我觉得应该是类似的,有兴趣的可以看看源代码的实现
QA
谢谢

模块化和组件化Css