以前最常用的工具是是xdebug加上Webgrind来检测,效果也不错。现在推荐另外一个工具:xhprof,facebook开源的工具。
最主要的是他提供了一个WEB方式的UI界面,提供的参数有:相应时间,内存占用,函数调用次数等,还有把每个函数调用的次数、执行时间和内存占用都有列出,让你一目了然,知道瓶颈在什么地方,看图说话:
请求总揽
函数调用情况
看到上面的效果是不是有点心动呢?开始进入正题。
安装
从pecl下载安装包,下载地址:http://pecl.php.net/get/xhprof-0.9.2.tgz
开始标准化的安装流程:
tar -zxvf xhprof-0.9.2.tgz
cd xhprof-0.9.2
/usr/local/php5.3/bin/phpize
./configure --with-php-config=/usr/local/php5.3/bin/php-config
make
make install
然后在你的php.ini加上:
extension=xhprof.so
[xhprof]
xhprof.output_dir=/data/tmp/ #日志文件保存路径
现在可以看看phpinfo();是不是已经有了xhprof的信息。到这里,安装就完成了。
应用
看官方推荐的标准例子:
// start profiling
xhprof_enable();
// run program
//这里就是你要检测的代码段,拿kohana为例,应该是:
require SYSPATH.'core/Bootstrap'.EXT;
// stop profiler
$xhprof_data = xhprof_disable();
//
// Saving the XHProf run
// using the default implementation of iXHProfRuns.
//
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default();
// Save the run under a namespace "xhprof_foo".
//
// **NOTE**:
// By default save_run() will automatically generate a unique
// run id for you. [You can override that behavior by passing
// a run id (optional arg) to the save_run() method instead.]
//
$run_id = $xhprof_runs->save_run($xhprof_data, "kohana");
echo "---------------\n".
"Assuming you have set up the http based UI for \n".
"XHProf at some address, you can view run at \n".
"http://<xhprof-ui-address >/index.php?run=$run_id&source=kohana\n".
"---------------\n";
这样每次访问这个脚本,都会在底部打印出类似这样的:————— Assuming you have set up the http based UI for XHProf at some address, you can view run at http:///index.php?run=4c7cd4869704f&source=kohana ————— 。这个是告诉你可以通过他的提供的工具来查看这次请求的分析结果,看第一步下载的xhprof-0.9.2解压后,里面有个文件夹xhprof_html,这里就是提供给我们看的工具。
查看结果
这里提供一个简单的方法,赋值xhprof_html和xhprof_lib到你的web目录,然后访问:http://your.domian/xhprof_html/index.php?run=4c7cd4869704f&source=kohana
是不是看到了和上面截图类似的界面,到这里就完成了。
查看资料:http://www.162cm.com/p/xhprofdoc.html
本文是在PHP5.2版本下试验,操作系统为centos。
废话不多说了,直接按步骤来。
第一步:安装PHP
去下载PHP的源码包,本文的源码包在所在路径为:/root/php-5.2.13,直接编译安装,安装过程不多说,如果你不清楚去网上搜索下,教程一大把。我安装在/usr/local/myphp/目录
第二步:新建一个扩展
网上的教程有,是用ext目录下的ext_skel脚本生成:
# cd /root/php-5.2.13/ext/
# ./ext_skel --extname=yzmf
上面这两行命令是生成了一个名称为yzmf的扩展。好了,按照教程要修改配置文件:
#cd yzmf //进入目录:/root/php-5.2.13/ext/yzmf
#vi config.m4
阅读全文…
什么是kohana?
Kohana 是一款纯 PHP5 的框架,基于 MVC 模式开发, 它的特点就是高安全性,轻量级代码,容易使用。
什么是smarttemplate?
一个轻量级的PHP模板引擎。教程见:http://bbs.chinaunix.net/viewthread.php?tid=593973
为什么要整合?
实在受不了模板里面还有那么多的$ <?php 这种符号,模板里面应该是要刨除掉这些php特有的符号。
阅读全文…
虫洞?看看爱因斯坦对虫洞的定义:“虫洞”就是连接宇宙遥远区域间的时空细管。暗物质维持着虫洞出口的敞开。虫洞可以把平行宇宙和婴儿宇宙连接起来,并提供时间旅行的可能性。虫洞也可能是连接黑洞和白洞的时空隧道,所以也叫”灰道”。看起来虫洞就是连接两个距离很远的物体。在我们的WEB项目中会存在这种情况吗?
假设你有一个域名:domain.com。现在主站是www.domain.com。好了,还有一个博客的子域名:blog.domian.com。现在有个需求:要在主站上调用博客子站里面的数据,而且是客户端(通俗的说是页面上)调用。你想到的有几种方式?这个是不是两个感觉很远的物体,好了,让我们来制造一个虫洞来连接这两个跨域的站点。
虫洞一:iframe
是的,iframe在不跨域子域的情况下完全可以互通。假如现在你要在http://www.domian.com/parent.html和http://blog.domain.com/child.html互通,那么在parent.html里面嵌入一个iframe,id为child,src指向child.html。只要满足一个条件:在两个页面上都这样设置:
document.domain='domain.com'
。这样设置之后两个页面的JS对象完全可以互通。在parent.html里面获得child.html的window对象:
var obj=document.getElementById('child').contentWindow
。这样obj对象就是child.html里面的window对象了,有了这个对象可以操作child.html里面的任何东西。在child.html里面操作parent.html更加方便:parent对象就是parent.html的window对象。
上面所说的iframe虫洞只能适用一些简单的需求,但是我接来下所说的一些却是以这个为基础的。 阅读全文…
kissy好像是淘宝开源出来的JS框架,官方更愿意称之为ui library。提供一些基本的dom操作,event util,cookie等。最惊艳的是datalazyload模块,真的非常非常的实用。不足的地方ajax方面还没整合进去,相信不久就会出来。
作为一个js框架,难免会拿来和目前非常火爆的Jquery来做比较,Jquery目前发展到1.4版本,比较稳定,而且新版本在性能上也有所提升,而且还有非常多的插件提供。但是kissy和jquery不同的是:在Jquery的世界里,都是Jquery对象,但是kissy没有这个概念,比如选择器:S.query(‘.date’) 这里得到的是一个数组对象,每个元素都是标准的dom对象。比如给所有的a标签增加一个class:DOM.addClass(‘a’, ‘val’)。这样感觉更像在操作DOM,而不是Jquery对象,给人的感觉更加亲近原生的JS,而不像Jquery那样和原生的JS隔离的那么远。
文档地址:http://kissyteam.github.com/kissy/docs/
源码地址:http://github.com/kissyteam/kissy
kohana是一款基于php5(5.2)的框架,MVC的模式,高安全性,代码轻量级。但是kohana并没有提供layout,至少我熟悉的2.3版本没有。在实际的开发过程中感觉到没有layout还真有点别扭,就想到自己开发一个layout的库类。
通过看kohana的手册和代码,了解到kohana是基于事件驱动的框架,输出之前的事件为system.display。所以可以添加一个这样的事件,在事件注册的方法中改变Kohana::$output的内容即可。库类代码如下: 阅读全文…
对于图片很多,而且很长的页面,也许第三屏后面的很少有用户滚动下去查看。如果图片也照样载入的话,是不是觉得有点浪费带宽,也浪费图片服务器的连接数。这个时候延迟载入很重要,按需载入。PV越大的效果越明显,废话少说,先看代码:
var LAZY=(function(){
var pResizeTimer = null;
var imgs={};
function addEventHandler (oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = fnHandler;
}
};
function resize(){
if(pResizeTimer) return '';
pResizeTimer = setTimeout(function(){
resize_run();
try{
clearTimeout(pResizeTimer);
}
catch(e){}
pResizeTimer=null;
}, 100);
}
function resize_run(){
var min={};
var max={};
min.Top = document.body.scrollTop + document.documentElement.scrollTop;
min.Left=document.documentElement.scrollLeft;
max.Top=min.Top+document.documentElement.clientHeight;
max.Left=min.Left+document.documentElement.clientWidth;
for(var i in imgs){
if(imgs[i]){
var _img=imgs[i];
var img=document.getElementById(i);
var width = img.clientWidth;
var height = img.clientHeight;
var wh=position(img);
if(
(wh.Top>=min.Top && wh.Top<=max.Top)
||
((wh.Top+height)>=min.Top && wh.Top<=max.Top)
)
{
img.src=_img.src;
delete imgs[i];
}
}
}
}
function position(o){
var p={Top:0,Left:0};
while(!!o){
p.Top+=o.offsetTop;
p.Left+=o.offsetLeft;
o=o.offsetParent;
}
return p;
}
return {
init:function(){
for(var i=0;i<document.images.length;i++){
var img = document.images[i];
var config={};
config.id = img.id;
config.src = img.getAttribute('_src');
if(config.src && !config.id){
config.id = encodeURIComponent(config.src) + Math.random();
img.id = config.id;
}
if(!config.id || !config.src) continue;
LAZY.push(config);
}
return LAZY;
},
push:function(config){
imgs[config.id] = config;
},
run:function(){
resize_run();
addEventHandler(window,'scroll',resize);
}
};
})();
使用方法很简单,2个步骤:
1 img的标签的src属性指向一个空地址,或者一个1×1的空白图片,_src属性指向实际图片地址,如:
<img src="" _src="path/to/img.jpg" />
2 在页面底部或者body onload里面:
在公司千万级的PV项目上使用了,据说效果不错喔!
此方法提供跨浏览器的事件操作。
提供的API有addEvent、removeEvent、getEvent等。具体的见代码:
var util=util || {};
util.Event = (function(){
var sUserAgent = navigator.userAgent;
var fAppVersion = parseFloat(navigator.appVersion);
var isOpera = sUserAgent.indexOf("Opera") > -1;
var isMinOpera4 = isMinOpera5 = isMinOpera6 = isMinOpera7 = isMinOpera7_5 = false;
var isIE = sUserAgent.indexOf("compatible") > -1
&& sUserAgent.indexOf("MSIE") > -1
&& !isOpera;
var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows");
return {
//获得事件对象,比如util.Event.addEvent(dom,'click',function(){var e=util.Event.getEvent();})
getEvent: function(){
if (window.event) {
return util.Event.formatEvent(window.event);
} else {
return util.Event.getEvent.caller.arguments[0];//调用此方法的函数的第一个参数
}
},
//获得时间的target,也就是事件的发生地,返回dom对象
getTarget: function(e) {
return e.target || e.srcElement;
},
//阻止冒泡,比如一个div里面嵌套了一个a,这两个标签都绑定了click事件,如果你想点击a标签的时候并不想执行div上面的click时间。可以用这个方法阻止
stopPropagation: function(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
else {
e.cancelBubble = true;
}
},
//阻止默认行为,比如一个a标签绑定一个click事件,如果你想阻止执行此事件之后并不做跳转,可以用这个方法
preventDefault: function(e) {
if (e.preventDefault) {
e.preventDefault();
}
else {
e.returnValue = false;
}
},
//阻止冒泡或者捕捉和阻止默认行为
stopEvent: function(e) {
this.stopPropagation(e);
this.preventDefault(e);
},
//增加一个事件 util.Event.addEvent(window,'load',function(){})
addEvent:function (oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = fnHandler;
}
},
//取消莫事件的绑定的某个函数
removeEvent:function (oTarget, sEventType, fnHandler) {
if (oTarget.removeEventListener) {
oTarget.removeEventListener(sEventType, fnHandler, false);
} else if (oTarget.detachEvent) {
oTarget.detachEvent("on" + sEventType, fnHandler);
} else {
oTarget["on" + sEventType] = null;
}
},
//格式化事件对象
formatEvent:function (oEvent) {
if (isIE && isWin) {
oEvent.charCode = (oEvent.type == "keypress") ? oEvent.keyCode : 0;
oEvent.eventPhase = 2;
oEvent.isChar = (oEvent.charCode > 0);
oEvent.pageX = oEvent.clientX + document.body.scrollLeft;
oEvent.pageY = oEvent.clientY + document.body.scrollTop;
oEvent.preventDefault = function () {
this.returnValue = false;
};
if (oEvent.type == "mouseout") {
oEvent.relatedTarget = oEvent.toElement;
} else if (oEvent.type == "mouseover") {
oEvent.relatedTarget = oEvent.fromElement;
}
oEvent.stopPropagation = function () {
this.cancelBubble = true;
};
oEvent.target = oEvent.srcElement;
oEvent.time = (new Date).getTime();
}
return oEvent;
}
};
})();
console是一个非常好用的日志调试对象,让你告别alert的调试工具。在Firefox中的Firebug插件中存在,在Chrom浏览器的开发工具,IE8的调试工具(启动调试)中。
下面列出这个对象所有的方法:
console.log():记录一行信息,无任何图标提示
console.debug():记录一行信息,带超链接,可以链接到语句调用的地方
console.error():向控制台中写入错误信息,带错误图标显示和高亮代码链接
console.info():向控制台中写入提示信息,带信息图标显示和高亮代码链接
console.warn():向控制台中写入警告信息,带警告图标显示和高亮代码链接
阅读全文…
JS中常用的有Array,Math,Date等对象,但是Error对象不常见吧,现在简单剖析一下。
一 定义
在JavaScript中Error类表示一个异常,是其他异常类的父类,构造一个Error类的基本语法为:
var objError = new Error(message);
Error对象具有name和message两个属性,name表示异常的类型,message表示异常详细信息字符串
JavaScript还预定义了其他一些异常类,这些类都是Error类的子类,如下:
1.EvalError //当不正确使用eval函数时,会抛出EvalError类的一个实例
2.RangeError //当数值超出JavaScript中合法的数值范围时,会抛出RangeError类的一个实例
3.ReferenceError //当读取一个不存在的变量的值时,会抛出ReferenceError类的一个实例
4.SyntaxError //当JavaScript中出现语法错误时,会抛出SyntaxError类的一个实例
5.TypeError //当JavaScript中类型不符合要求时,会抛出TypeError类的一个实例
6.URIError //当字符串不符合编码或解码要求时,会抛出URIError类的一个实例
二、用法
为了说明如何在JavaScript中使用异常机制,我来用代码说明,这样会更加清晰:
try{
...
}catch(error){
throw new Error("对不起,出错啦!");
}
//或者这样:
if(some false){
throw new Error("对不起,出错啦!");
}