西红柿爱番茄

Feed Rss

最近突然脑子一热,Read It Later好、Instapaper也好,保存的网页都是在别人的服务器上,使用别人的工具来浏览,总感觉受牵制,干脆自己倒腾一个这样的工具,把数据提交到自己的网站空间里,之后使用Ipod Touch来看,这个更有保障,功能其实也就需要一个保存网页的URL并且在空闲的时候浏览,简单的一个收藏夹。并且可以顺便尝试使用Youtube的UIX事件机制。

了解更多

2011-1-17 updates:

今天在给组内介绍这个东东的时候,有提出是否使用这个工具后的开发方式,是否会依赖于这个工具进行开发。我想这要分两种情况:

  1. 如果在一个页面内开发的话,那么就可以使用行内压缩的方式,在标签里添加几个标记,而不会影响到页面的正常的标签。不使用该工具的话,完全可以将这些标识去掉。
  2. 如果是使用include的方式的话。那么既然使用了这种方式,那么就必然需要使用一个编译程序来编译你的include语法,这样对于使用什么工具开发,都会依赖于该工具。在这里只是使用了include的方式,并添加了一个压缩、语法检查,如果需要原始未压缩版的,那么完全可以使用不压缩的方式,编译出来之后就是完整的一个页面,毫无副作用。

当初就是为了能够使得页面内就可以进行压缩,才添加了c:和compress语法。当初的这样的做法,也是为了适应当前自己做的项目出发的。

详细说明图示

============ updates分界线 =============

在平时开发的过程中,一直都在使用这个工具来压缩、纠错等等,但是在不同的文件中可能是不同的,有些需要编译的文件可能是只对HTML标签进行压缩、或者对页面行内js、css进行压缩,如果都使用include的方式,可能就太局限了。因此,对编译程序又作出了修改。

此次修改点包括:

  • 添加页面内标记有compress的script、style标签的压缩
  • 对HTML标签使用c:标记的标签压缩
  • 去掉了cscript.exe来执行js代码,进行纠错的功能

说明:

对行内js、css压缩的语法:

[html]
<script compress id="test">…</script>
<style compress>…</style>
[/html]

对HTML进行压缩的语法(要配对的使用c:进行开始和结束标签的标记):

[html]
<c:head>
<meta charset=’utf-8′>
<title>Template</title>
</c:head>
[/html]

之前本来打算对script、css、html标签进行相同的c:标记处理,但是script、css进行这样标记之后,在一些编辑器(Editplus等)中,代码高亮、自动完成功能都会失效,所以还是使用独立的compress的属性方式了。

最新编译程序下载:build-1-1-1.rar

具体的安装和使用方式,请浏览:Perl build程序升级build-1-0-8

eBay(http://www.ebay.com/)

  • 整个页面都进行了压缩,不管是行内js、css还是外联的,以及HTML代码,都压缩了,这点做的比较到位,而且不能是纯手工来做的。这点符合我最近的想法,使用工具来完成这个事情,那么在提交给QA测试的时候,页面就必须是全面压缩过的,勇于试错,踩的坑多了才能避免后面的人踩的坑更少。
  • 看到很多网站都有这样的link元素声明:
    <link rel=”canonical” href=”http://www.ebay.com”>
    查阅之后,才知道又是为了SEO上的优化,避免搜索引擎重复收录同样的页面。
    http://www.fqyy8.com/archives/3045.html
  • Body标签内中的style、script行内样式、脚本比较多,而且外联的几个js文件也夹杂在其中,所以从HTTP瀑布图来看,造成了阻塞,好在FF在js的加载方面提升了,能够跟其他的资源并行加载。
    当然这样做的目的很多,有一个目的叫做“让功能尽早可用,当功能不可用的时候,让关键的功能稳步退化可用”,那么从这个角度来考虑,在head加载js、或者在body内加行内js,就情有可原了,让js紧随HTML结构的后面,可以使得脚本尽快的执行,但是要注意在IE6下的终止错误,将js行内脚本跟需要处理的HTML标签的父元素并行。
    对于页面初始化的js,放到head标签内比较合理,维护方便。
  • 由于页面meta、link、charset、doctype等声明在各个网站中都有所不同,所以需要整理出来哪些是必须的(SEO、性能优化、浏览器兼容doctype等),并且通过一个工具来检查,后期打算做这样的一个工具,集成到firebug中,方便使用。比如,eBay的首页页面源码中出现了两个meta charset声明。
  • 页面头部使用了三个css文件,并且标记了版本控制,这样的方式,使用Combo的方式很不错的选择。
  • 不得不说,ebay的js的命名空间,不是一般的长:vjo.dsf.error.ErrorHandlerManager.enableOnError
    如果没有一个健全的API文档、或者使用IDE进行自动提示,那么在编写的时候很容易出错,也不方便代码的编写。这些命名空间都是通过vjo.ctype创建出来的,并且链式使用protos附加构造函数,并且还有一个needs的函数用于标记该命名空间需要其他的命名空间的支持。用vjo.ctype创建出来的,缈似一个个模块,之后在页面中直接调用。

YouTube(http://www.youtube.com/)

  • 页面使用了HTML5的doctype,可是却没有见到charset的声明,整个head都没有,而是直接来了一几段js代码。但是在开头看到这样的一段代码用于统计时间信息的:
    [javascript]
    try {
    yt.timing['srt'] = window.gtbExternal && window.gtbExternal.pageT() ||
    window.external && window.external.pageT;
    } catch(e) {
    }
    if (window.chrome && window.chrome.csi) {
    yt.timing['srt'] = Math.floor(window.chrome.csi().pageT);
    }
    if (window.msPerformance && window.msPerformance.timing) {
    yt.timing['srt'] = window.msPerformance.timing.responseStart – window.msPerformance.timing.navigationStart;
    }
    [/javascript]
    这里用到了Chrome浏览器独有的chrome对象扩展,同时,也使用了IE9中msPerformance对象的扩展属性,用于收集一些助于分析性能的信息,之前就看过IE9有这玩意,在这里看到使用场景了,YouTube还真不赖,创新不断,看来还真是“创新是需要勇气”滴。
    http://ecmanaut.blogspot.com/2010/06/google-bom-feature-ms-since-pageload.html
    这样做的目的,可能是使得在页面刚开始加载的时候就统计时间信息,减少误差。
  • 使用img在页面解析的时候首先进行DNS Lookup:
    [javascript]
    yt.preload.start = function() {
    var img = new Image();
    yt.preload.videoConnection = img;
    img.onload = img.onerror = function () {
    delete yt.preload.videoConnection;
    };
    img.src =
    ‘http:\/\/v5.lscache2.c.youtube.com\/generate_204?sparams=id%2Cexpire%2Cip%2Cipbits%2C
    itag%2Calgorithm%2Cburst%2Cfactor%2Coc%3AU0dYSVlLU19FSkNNOF9RRVdH&fexp=910102&algorith
    m=throttle-factor&itag=34&ipbits=0&burst=40&sver=3&signature=A1791B339659467A5233C71BD
    394ECC299548EBE.88354CA11413C832E67AA3411C7D119E7F024521&expire=1294905600&key=yt1&ip=
    0.0.0.0&factor=1.25&id=d689799c76e71c93′;
    img = null;
    };
    yt.preload.start();
    [/javascript]
    这样做的目的在于,为接下来的视频的加载提前进行了DNS Lookup,减少视频加载的时间。在视频详情页是看不到这个img提前进行DNS Lookup脚本的,因为已经没必要了,进行了配置。
    或者可以利用这个时间信息进行判断,进行用户体验上的稳步退化、或者进行额外的加载策略。。。
  • 对于页头logo的设计上,使用了一个1*1像素的透明图片,然后对它进行定宽高,并且添加背景。刚开始看这个还不明所以,看过那个大sprites之后,突然恍然大悟。为啥人家的sprites可以拼凑的那么密密麻麻,而且还互相不受影响,原来都是定宽高了。
    对于为啥使用图片的方式,那是因为YouTube基本整站的背景修饰样式,都是使用1*1的透明图片、定宽高、应用背景的方式,整个页面使用一个图片。
    图片的URL忽略了host://s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif,这样在http、https下浏览页面都没问题。不过需要注意的是,使用这种方式应用在CSS文件上,在IE下会download两次。
    使用图片的方式,对于应用背景就更加的独立,扩展好,提高复用度,在CSS的编写上就更加的少了。
    但是这种方式,也有缺点:

    1. 对图片进行缩放,在页面渲染上至少会花费更多的性能,对于大宽高的话,性能消耗会很明显。
    2. 必须对图片进行宽高的限定,否则会露馅,因此适用的范围会比较小。
  • 在底部页码的实现中,使用了button的方式,而不使用超链接,估计是从统一页面样式上的考虑吧,页码看起来更像是一个个按钮。在每一个按钮上处理window.location.href为该button的href属性值。使用window.location.href来导航会导致这样的一个问题:目标页中在IE下document.referrer会丢失。不管是使用localtion.href、window.open、提交表单等方式,都会导致document.referrer丢失。
    http://www.imkevinyang.com/2010/01/document-referrer%E4%B8%A2%E5%A4%B1%E7%9A%84%E5%87%A0%E4%B8%AA%E5%8E%9F%E5%9B%A0.html
  • 在js代码中,看到最多的莫过于yt.setConfig、yt.pubsub.subscribe,这个整体看起来页面就想通过配置拼装起来的一样,对于每一个模块,使用配置来使得模块根据显示声明的方式来工作。通过查看这个js文件:
    s.ytimg.com/yt/jsbin/www-core-vflv-060B.js
    Youtube的这个js库封装了window下的一些方法,基于yt的命名空间,这种调用方式很新颖。
  • 之前看过YouTube的开发人员介绍过UIX widget system。在一些button按钮上已经看到有uix的命名空间了。现在来简要的说一下这个UIX,它是利用事件冒泡的机制,将需要的事件类型都绑定到document上,之后每一个button触发各种类型冒泡到document上,并执行相应的事件逻辑程序。
    UIX system在register的时候,需要使用一个class进行标识,并提供相应的事件类型、处理函数。所以这里就有两层的事件绑定,一个是document,一个是具体的事件源DOM元素。使用class的方式一个是从“物以类聚”的性质来考虑,可以在多个按钮上使用系统的class,一个是达到了样式通用,另一个是事件标识通用。
    但是这样会不足够的灵活,事件逻辑跟样式耦合在一起,而且在维护上会有一定的风险,万一class给改掉,那就over了。
    所以,我比较倾向于使用自定义字段的方式,使用自定义的话,这个就将UIX完全的独立出来了,而且也可以通过给自定义字段设置相同的属性值来达到“物以类聚”的功能。简单的示例如下:
    [html]
    <button id="btn1" data-uix="btn_uix_click1">猛击吧1</button>
    <button id="btn2" data-uix="btn_uix_click2">猛击吧2</button>
    <button id="btn3" data-uix="btn_uix_click3">猛击吧3</button>
    [/html]
    [javascript]
    var addEvent = function(e,t,f){
    (addEvent = e.attachEvent ? function(e,t,f){
    e.attachEvent("on"+t,function(){f.call(e);});
    }: function(e,t,f){
    e.addEventListener(t,f,false);
    })(e,t,f);
    }

    //UIX control
    var UIX = UIX || {
    "registry":{},
    "register":function(type,uixes){
    if(!this.registry[type]){
    this.registry[type]={};
    }
    for(var uix in uixes){
    if(uixes.hasOwnProperty(uix)){
    this.registry[type][uix] = uixes[uix];
    }
    }
    },
    "handleEvent": function(evt){
    if(evt.type in this.registry){
    var actions = this.registry[evt.type];
    for(var uix in actions){
    el = evt.target || evt.srcElement;
    if(el.getAttribute("data-uix") == uix){
    actions[uix].call(el,evt);
    }
    }
    }
    }
    };

    UIX.register("click",{
    "btn_uix_click1":function(){alert("btn_uix_click1");},
    "btn_uix_click2":function(){alert("btn_uix_click2");},
    "btn_uix_click3":function(){alert("btn_uix_click3");}
    });

    addEvent(document,"click",function(e){
    UIX.handleEvent(e || window.event);
    });
    [/javascript]

最近一直在总结自己的东西,整理了一下自己在前端开发过程中使用的比较多、使用起来比较顺手、开发效率快、适合自己开发习惯的一些工具,同时还有一些辅助的工具:移动设备、虚拟机等,这些在管理自己的时间、项目、计划方面都非常的实用。但是最重要的一点是:重装系统之后,我就可以按照这个工具表来搭建自己的开发环境,着手开发。

了解更多

Goo(http://www.goo.ne.jp/)

Goo是日本的综合门户和搜索引擎, 隶属于日本最大电信公司NTT

  1. 通过查看HTTP瀑布图,在对不同性质的资源进行不同的域名管理方面,不甚合理。CSS、JS、Image等资源很多都还部署在主域goo.ne.jp下,而且在页面的很多修饰图片方面也比较零散,很多没有使用sprites的方式,导致过多的HTTP请求。
  2. 页面对js、css的优化似乎都做了处理,css在top、js在bottom,在HTML内容中穿插了一个加载广告用的document.write。这个好坏就不说了,这个document.write所加载的js还是一个动态的页面,还要依赖于该页面进行进一步的跳转来读取js文件,如果只是为了传递参数、在广告 (ad.nttnavi.co.jp)那边的服务器做判断的话,那么直接在js文件后面添加参数即可,而又何必使用这样的一个中间页面来做跳转呢(经过测试,使用这样的一个中间页读取另外的内容,之后将内容发送会客户端,所花费的时间比普通的直连文件的方式都要长,不管是将几个请求文件压缩为一个,最后返回。具体的测试请查看http://www.ilovejs.net/archives/449)。如果在服务端无法监控到每一个请求,并对该请求的参数进行判断、转发的话,退而求其次,使用服务端语言的中间页面来做判断,也就有些道理了,简单有保障。
    为了保证广告一定可以出来,还是用上了noscript标签来加载一个图片。
  3. 搜索框中的suggestion做的很不错,展示了二次内容的选择,sug的内容是从search.goo.ne.jp传过来的数据,整个suggestion功能所使用到的css、js、数据都是来自这个域下,请求数据使用的是jsonp的方式,而没有使用简单的document.domain的方式,在主域和子域之间跨域。这个就看search.goo.ne.jp和goo.ne.jp的关系了。
    不过它的这种suggestion的方式,还是首见的,创意很好。展示了更多的suggestion,对于用户或许是更好的用户体验、更多的选择,对站点来说,或许还是一次很好的卖点。
  4. 不过在输入框中使用了这样的一个样式属性:ime-mode。这个属性也是第一次看到,具体的作用查阅文档之后还是不太明了。不过它造成了Firefox下的问题,在切换tab的时候,首次获得了焦点,当点击输入框的时候,失去焦点,再点击输入框无法获取焦点进行输入了,要过几秒钟哇,还是随机的。
  5. 在右栏下边的关于时间点的内容切换中,一来没有使用按需加载的方式(这个估计跟架构上相关了,看是否支持这种自由的拉取数据的方式);二来是静态内容,不包含任何内容,在li标签中使用div标签又包含了一层,不妥哇,即使是后期可能会在其中包含链接、图片啥的,有没div对展示内容都不受影响的。
  6. 可能最受我关注的是,是它对页面点击统计的方式,因为最近我也是一直在忙于点击统计的设计和重构,所以当看到goo的时候,发现了它进行了点击统计,所以分析了一番。
    Goo基本对页面的每一个超链接都进行了统计,因为它对输出的每一个超链接设置了一个唯一的id,这个唯一的id,这个唯一的id的格式是(\w)-(\w+)-(\d)。从页面结构分析,第一个是表示大的分块区域,中间的是这个块内的小块,第三个是链接的索引(在块内按照HTML结构的排序)。
    刷新页面之后,内容变化了,但是这个唯一的id还是不变的。那么这么设置有这样的好处:用户点击了哪里、点击的是哪一小块、点击的是哪一条、点击之后到哪个页面、块之间的切换等这些信息,同时,还简化了点击的事件逻辑,减少点击日志的丢失率(如果事件逻辑太过复杂,那么在点击事件发生过于频繁的时候,会造成一定的执行延迟,之后用户再关闭浏览器,那日志就丢失了)。最主要的是在还原页面的点击信息方面方便简单,对信息进行归类,之后在后台显示点击次数、点击顺序图、热力图方面都比较方便。
    而且这样在页面改版的时候,对这些分块的逻辑不变,那么后端的解析程序,还是可以完好的跑。前端的解析脚本也可以完好的跑。
    缺点就是增加了页面的体积,增加了过多的id数量。
    还有一点就是:发送这个日志的方式,却是使用动态创建一个iframe,并指定iframe的src来发送请求,怪哉!使用动态创建Image的方式不是简单直接的多么。
    其他的使用delegate、在父元素上定义块级标识、动态去算每一个超链接的索引的方式,都增加了事件逻辑的复杂度。但是这种方式,可以一方面减少页面体积,另一方面是在多人合作的时候,可以完全不管这个点击统计的存在,只要父元素中标识好块信息,管里面怎么折腾。但是这算超链接的索引的,可就需要花费一些心思来考虑到大部分的情况了。