Watch对象更新

这次对Watch对象添加了一个新方法:iterate。主要是用于这样的情况,同时测试多个指定循环次数的情况,比如可以同时指定1000、2000、3000、4000…等等,通过iterate方法,就可以查看到几个测试用例在这几个循环次数下的时间消耗,iterate的用法如下:

Watch.iterate({
  "title":["getElementsByTagName","childNodes"],
  "loop":[1000,2000,4000,5000,10000,20000,40000,100000],
  "interval":1500,
  "fn":[
    function(){ document.getElementById("div").getElementsByTagName("p");},
    function(){  document.getElementById("div").childNodes;}
  ]
});

iterate方法带有一个对象字面量参数,这个对象字面量的参数的属性包括title数组、loop循环次数数组、interval更新显示的时间间隔、fn测试函数数组。说起来可能比较虚,看例子吧:Watch.iterate()

flush()和ob_flush();flush()组合的差别

2010-7-29 Updates:

如果将render解析为“呈现”,即是将元素显示到视窗中,那么Nicholas的说法在大部分浏览器下是正确的,经过下面使用PHP方式的测试,在没有将闭合标签加载下来之前,页面无法显示h1标签内容,但是IE除外,它仍然显示内容和应用样式。

同时还有一点需要说明的是:一些文章说在head和body之间插入flush()方法来尽早的输出head的内容,以至于尽快的下载样式资源,这也是有一定道理的,但是由于刷新输出的head内容是不可见的,所以页面上还是会一片空白,等待内容的呈现。所以比较合理的做法是将内容分块,或者将页面内容分为head、body、footer等俺顺序使用flush刷新输出,这样就使得有一个比较流畅的页面显示效果。

本人的blog正在这样实践着……

————————纠正分界线—————————

在Nicholas的一个PPT中看到了这句话“The browser won’t render a block-level element inside of <body>
until the closing tag has been received”,意思就是“在body中,浏览器在一个块级元素的闭合标签未加载下来之前不会渲染该元素”,第一次看到这样的说法,感到很奇妙,到底是不是真的呢?

首先,使用javasript来进行测试,在一个块级元素中嵌套一个脚本,来获取该块级元素的innerHTML,《测试用例》,测试结果上面的说法错误。

接着测块级元素的style,使用js输出块级元素的style属性值,《测试用例》,测试结果上面的说法错误。

接着使用PHP的方式,在块级元素的闭合标签前面加上<php flush(); sleep(3); ?>,来查看是否会刷新输出内容,测试结果就是文章标题中所说明的问题,使用flush()和ob_flush();flush()组合的结果是不同的,并且在不同的浏览器下行为又有所不同。《flush()》,《ob_flush();flush()》。

PHP的测试结果为:使用flush()的形式的时候,Opera、Chrome、Safari、IE并没有在flush执行的时候刷新输出前面的内容;使用ob_flush();flush()组合的时候,Opera、Chrome、Safari、IE可以刷新输出前面的内容,但是这里又有个小插曲,IE可以输出元素闭合标签之前的内容,并可以渲染样式,但是Opera、Chrome、Safari只输出该元素之前的内容,该元素内的文本内容不会刷新输出。或许大家没有看到我提及Firefox浏览器的情况,经过测试,Firefox杯具的是两种形式都不会刷新输出内容,需要等到整个HTML文档加载完成才显示页面。为此,应该避免下面的情况:

  <div>Hello baby,www.ilovejs.net is here...<?php ob_flush();flush(); ?></div>
  <!--或者-->
  <div>Hello baby,www.ilovejs.net is here...<?php flush(); ?></div>

经过这些测试,可以得到明显的结论:在输出刷新方面,尽量使用ob_flush();flush()组合,并且避免在HTML标签的闭合标签之前刷新输出。

图片导航设计方案

2010-7-29 Update:

在第一种实现方案中,如果图片的父元素设置了padding、margin之后,就会使得FF、Chrome等逻辑判断失误,而IE还完好。

———————-纠错分界线————————–

说“图片导航”或许很迷糊,我也迷糊不知道怎么描述,就是类似于Google、QQ空间、百度图片搜索中的在图片中出现上下箭头或者左右箭头来指示下一个和上一个图片的功能。昨天同事问到我这方面的实现方式,也就暂时想了两种。

之前查看过Google的方法是在图片上添加两个HTML元素作为逻辑操作对象(包括切换鼠标样式、点击事件等),这样就显得比较复杂了,需要确定图片的在页面中的位置、图片的宽高、之后还要判断鼠标的位置……QQ空间的相册导航,是在图片本身来操作逻辑的,这同我第一种方案很类似,而百度图片搜索结果页中图片导航是在图片的父元素中做逻辑的,这样就避免了图片大小对导航的干扰的问题(主要是如果图片太小,在图片上做导航就显得迷糊了,特别是鼠标的样式切换)。下面来说说我的方法。

第一种,直接在图片上做逻辑。事件参数e有这么两个参数,在FF等浏览器下是layerX,layerY,在IE下是offsetX,offsetY,用于在一个DOM元素触发事件的时候,鼠标在该元素上的偏移量。这个是好方法啊,在结合offsetHeight和offsetWidth,就可以直接在图片上做判断了,给图片添加mousemove、onclick事件来处理鼠标样式切换、点击事件逻辑等等。《测试用例1》,可是这种方法的一个缺点是:在IE6下,当鼠标移动到鼠标的时候,会默认的弹出一个框,很杯具。

第二中方式就是根据上面的技巧,在图片上覆盖一个div(或者其他的能覆盖的元素都成),覆盖就得获取到图片在页面中的坐标以及宽高了,通过offsetLeft和offsetTop可以方便的得到,兼容性也还好,对于不是非常复杂的DOM结构和CSS布局,应该都是没啥问题的。《测试用例》,这样就避免了IE6下弹出框的问题。不过这样代码就得写多几行了。

具体的实现方式可以查看上面给出了两个实例。

javasript预读机制小析

javasript的预读机制说的直白点就是其他语言中所谓的“编译”,在代码运行之前对代码进行review一遍,把一些使用var和function声明的变量和函数提起读进内存里,并分配空间,初始化为undefined。等到代码运行的时候再进行相应的赋值。

简单的预读原理,相信很多人都已经知道了,比如:

alert(test);  //output:undefined
var test = "supersha";
//=========================
alert(typeof fn); //output:function
function fn(){}
//=========================
alert(typeof fn2); //output:undefined
var fn2 = function(){}

上面是非常普通的原理,大家都能理解。但是有两个对于新手来说比较难懂的方面:“函数第一,变量第二”、“作用域环境”。

“函数第一、变量第二”,在这里的意思是在预读过程中,当遇到使用function声明的函数的时候,会先预读,即时后面使用var声明了同名的变量,也不会在内存中覆盖;而使用var声明的变量会受到后面使用var声明的同名变量的覆盖。需要注意的是,使用var的形式声明的函数字面量在预读的时候也是被当作一个变量来对待,它会受到同名变量的覆盖。但是,这里所的覆盖有一个大前提,需要在同一个作用域内。这就是“作用域环境”的意思,需要明白这点:在不同的作用域内,使用var声明的同名变量、函数在预读的时候是互相不干扰的。比如:

var url = "www.ilovejs.net";
function fn(){
  alert(url);  //output:undefined
  var url = "www.ilovejs.com";
  alert(url); //output:www.ilovejs.com
}
fn();
alert(url); //output:www.ilovejs.ne

上面的情况就涉及到作用域环境的问题了,两个使用var声明的url变量在不同的作用域内,相当于“独立”的变量,互相不干扰。