Flickr使用YUI3重构时遇到的问题
上周做YUIConf2010介绍分享时没有作为重点的《Porting Flickr to YUI3》却被大家关注。所以回来仔细看了一遍Video又得到了新概念——感知性能。
《Porting Flickr to YUI3》的分享者Ross Harmes是flickr的前端开发工程师,在这次会议上他主要分享了他的团队在运用yui3时的性能,组件,技巧,经验。几个月前,Flickr推出了新的照片网页,他们决定使用YUI3彻底推倒重建旧的页面,使用YUI3是件快乐的事情,但也总结了一些问题:
第一个问题:延迟的js
为了不让js堵塞页面加载,一般都是将页面的js代码移动到页面底部,但是问题产生了,这样一些完全依赖js的ui元素将无法可用,必须要让用户等待到js加载完成后才能操作。flickr的照片页面这个等待过程一般情况下是2s,再ie下更加严重。比如一些连接、按钮在等待js加载完之前人们为了友好性会给用户一个连接响应,让用户另跳到页面继续操作,但是这不是一个很好的解决方法。
flickr采取的解决方案是动态排队,提高用户的感知性能。其实就是为用户增加一个响应的效果,flickr举的例子是他们页面上的一个导航提示层,如图:
flickr将原生的js(动态排队)的功能内嵌到页面顶部,而YUI3所有内容包括seed全部移动到页面底部。顶部代码如:
(function(F) { var geoOverlay1, geoOverlay2, last_context_clicked; F.actionQueue.register('button-bar-options', { interim: function(id) { var button = document.getElementById(id); if (button.className.search(/ActiveButt/) === -1) { button.className = button.className + ' ActiveButt'; } button.blur(); if (!document.getElementById('interim-menu-action')) { var fake_menu = document.createElement('div'); fake_menu.id = 'interim-menu-action'; fake_menu.className = (document.getElementById('button-bar-fave')) ? ((document.getElementById ('button-bar-fave').className.replace(/fave-button/, '').search(/fave/) !== -1) ? 'interim-menu interim-menu-fave': 'interim-menu') : 'interim-menu interim-menu-owner'; fake_menu.innerHTML = '<div class="interim-menu-arrow">◢◣</div>' + '<div class="interim-menu- arrow-mask"></div>'; document.getElementById('nav').appendChild(fake_menu); } if (document.getElementById('interim-menu-share')) { var fake_share_menu = document.getElementById('interim-menu-share'); fake_share_menu.parentNode.removeChild(fake_share_menu); if (document.getElementById('button-bar-share')) { document.getElementById('button-bar-share').className = document.getElementById('button-bar- share').className.replace(/ActiveButt/, ''); } } }, cleanup: function(id) { var fake_menu = document.getElementById('interim-menu-action'); if (fake_menu) { fake_menu.parentNode.removeChild(fake_menu); } F.actionQueue['photo-button-bar'].display_action(); } }, 'photo-button-bar'); } (F));
这样做的目的是在yui3没有加载完成前,用户点击操作显示的弹出层是js原生onclick执行(创建正在加载中的外框)。而具体需要显示的内容给用户一个等待加载的过程,在暗示用户心理的过程中,页面已经加载完js(包括页面底部的YUI3各种模块加载),并显示出用户需要的内容。这就叫感知性能的提升。
这个过程没有真正提高页面js加载速度,反而会相应的增加些,但是产生的结果对用户而言确实是提升了体验,这一点很有意思,所以有时性能与感知要有一个权衡。
第二个问题:Y.delegate()和Y.on()的_poll方法导致轮询
然而提高了用户可感知性,便遇到另一个问题,如果用户不去点击那个弹出层,也就是具体操作的Dom对象不存在,当yui3加载后的Y.on()将无法找到对应的dom对象,导致Y.on()一直在轮询。
Y.delegate()与Y.on()的事件监听检测机智虽然非常之像样,但是同样导致一些性能损耗,因为检测的过程是不停的去判断DOM的存在情况,直到DOM已经加载完。
为了避免这种情况,flickr将所有点击后显示的dom都采用display:none的形式保证在Y.on()之前存在dom对象。至于动态排队的显示框与加载后的显示框是完全没有关系的,当具体操作的js执行时,将移出之前动态创建的元素,显示出隐藏的内容。
第三个问题:过长的URL
flickr的combo-handler URL 有2,792characters,而少数用户的防火墙是限制url的长度,因此这一点需要大家注意,flickr使用一定的算法减少40%字符。但是有人提出一个更好的解决方法就是在加载完模块后进行检测如果存在没有加载的模块之后再次加载剩余模块。
flickr最后总结要去深入的挖掘js文档库,才能真正的运用yui3 提高性能。
flickr目前只是改版了照片页面,地址为 http://www.flickr.com/photos/42924197@N02/5105361222/in/photostream/