Console详解 (2011-10-27)

 console.log(object[, object, ...])

在控制台输出一条消息。如果有多个参数,输出时会用空格隔开这些参数。

第一个参数可以是一个包含格式化占位符输出的字符串,例如:

console.log("The %s jumped over %d tall buildings", animal, count);

上面的例子可以用下面的无格式化占位符输出的代码替换:

console.log( " The " , animal,  " jumped over " , count,  " tall buildings " );

并且,这两种方式是可以组合使用的。如果使用了格式化占位符,而提供的参数的个数多于占位符的个数,那么,多余的参数会以空格分隔的方式附加在字符串后面,就像:

console.log( " I am %s and I have: " , myName, thing1, thing2, thing3);

如果参数是一个Javascript对象,那么在控制台输出的就不是静态文字,而是一个可交互的超链接,点击超链接可以查看该对象的HTML, CSS, Script, DOM窗口,可用格式化字符串%o代替Javascript对象。

console.log( " Body tag is %o " , document.body);

格式化字符串列表:

格式化字符串 类型
%s 字符串
%d, %i 整型(暂不支持数字型)
%f 浮点型 (暂不支持数字型) 
%o 链接对象

console.debug(object[, object, ...])
在控制台输出一条消息,包含一个指向代码调用位置的超链接。假如是直接在控制台输入该命令,就不会出现超链接(和console.log()一样)。

console.info(object[, object, ...])
在控制台输出一条带有“信息”图标的消息和一个指向代码调用位置的超链接。

console.warn(object[, object, ...])
在控制台输出一条带有“警告”图标的消息和一个指向代码调用位置的超链接。

console.error(object[, object, ...])
在控制台输出一条带有“错误”图标的消息和一个指向代码调用位置的超链接。

console.assert(expression[, object, ...])
测试表达式expression是否为真。如果不是真,会在控制台写一条消息并抛出异常

console.dir(object)
以列表形式输出一个对象的所有属性,有点和你查看DOM窗口相类似。

console.dirxml(node)
输出一个HTML或者XML元素的XML源代码。和你在HTML窗口看到的相似。

console.trace()
Prints an interactive stack trace of JavaScript execution at the point where it is called.

The stack trace details the functions on the stack, as well as the values that were passed as arguments to each function. You can click each function to take you to its source in the Script tab, and click each argument value to inspect it in the DOM or HTML tabs.

console.group(object[, object, ...])
输出一条消息,并打开一个嵌套块,块中的内容都会缩进。调用console.groupEnd()关闭块。该命令可以嵌套使用。

console.groupEnd()
关闭最近一个由console.group打开的块。

console.time(name)
创建一个名字为name的计时器,调用console.timeEnd(name)停止计时器并输出所耗时间(毫秒)。

console.timeEnd(name)
停止同名的计时器并输出所耗时间(毫秒)。

console.profile([title])
打开Javascript性能测试开关。可选参数title会在打印性能测试报告时在报告的开头输出。

console.profileEnd()
关闭Javascript性能测试开关并输出报告。

console.count([title])

Writes the number of times that the line of code where count was called was executed. The optional argument title will print a message in addition to the number of the count.

 

点击查看原文阅读(303) | 评论(1) | 分类:前端开发HTML5/JS

PHP抽奖程序之几率算法 (2011-10-26)

做PHP确实很少接触算法问题
前几天遇到一个PHP几率算法问题,很有意思,
大致就是一个抽奖程序
贵重物品出现几率低,便宜物品出现几率高
网上找打了答案,在下面评论中看到了另一种方法,我觉得更好,效率更高

转来这个问题,和我之前遇到的差不多,
问题是这样子的:在一个物品合成系统中,需要使用几件不同的物品来合成宝石,有不同的几率生成一颗(50%)、两颗(16%)和三颗(2%)宝石,其余的为爆掉,即什么也得不到。

//初始化数组
$stone_arr = array( 
		array( 'num' => 1, 'prob' => '50%' ),
		array( 'num' => 2, 'prob' => '16%' ),
		array( 'num' => 3, 'prob' => '2%' )
		 );
//随机获得一个幸运数字
$luck_num = mt_rand( 0, 99 );
//初始化几率区间和最终宝石生产数目
$lucky_range = $made_num = 0;
 
foreach( $stone_arr as $sa ){
	$prob = intval( $sa['prob'] );
	if( $luck_num >= $lucky_range && $luck_num < $lucky_range + $prob ){
		$made_num = $sa['num'];
		break;
	}
	else{
		$lucky_range += $prob;
	}
}
 
for( $i = 0; $i < $made_num; $i++ ){
	//生产宝石的逻辑
}
 

然后是第二种方法,我喜欢的方法,不知道数量多了效率会不会也有问题

$a = array_fill(0,50, 1);
$b = array_fill(0,16, 2);
$c = array_fill(0,2, 3);
$d = array_fill(0,32, 0);
$arr = array_merge($a, $b, $c);
//var_dump($arr);
$d = mt_rand(0,99);
echo $arr[$d];	

点击查看原文阅读(521) | 评论(0) | 分类:算法,逻辑分析

基于Comet服务器推技术 (2011-10-24)

 最近一直关注COMET推技术,现在已经应用很普遍了
比如renren,新浪微博,都用到了COMET技术
大部分使用java实现的,下面是用PHP实现的原理

原理:利用htmlfile这个ActiveX,往页面上放一个iframe,设置它的src为请求的地址。
comet php

1.我们需要一个持久链接的HTTP请求
2.需要一个加载javascript的html页面

这个脚本会做一个无限循环,将返回服务器的时间,只要客户端连接。

<?php
 
  header("Cache-Control: no-cache, must-revalidate");
  header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  flush();
 
  ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
 
    <title>Comet php backend</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
 
  <script type="text/javascript">
    // KHTML browser don't share javascripts between iframes
    var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
    if (is_khtml)
    {
      var prototypejs = document.createElement('script');
      prototypejs.setAttribute('type','text/javascript');
      prototypejs.setAttribute('src','prototype.js');
      var head = document.getElementsByTagName('head');
      head[0].appendChild(prototypejs);
    }
    // load the comet object
    var comet = window.parent.comet;
 
  </script>
 
  <?php
 
  while(1) {
    echo '<script type="text/javascript">';
    echo 'comet.printServerTime('.time().');';
    echo '</script>';
    flush(); // used to send the echoed data to the client
    sleep(1); // a little break to unload the server CPU
  }
 
  ?>
 
  </body>
  </html>


创建客户端脚本

var comet = {
    connection   : false,
    iframediv    : false,
 
    initialize: function() {
      if (navigator.appVersion.indexOf("MSIE") != -1) {
 
        // For IE browsers
        comet.connection = new ActiveXObject("htmlfile");
        comet.connection.open();
        comet.connection.write("<html>");
        comet.connection.write("<script>document.domain = '"+document.domain+"'");
        comet.connection.write("</html>");
        comet.connection.close();
        comet.iframediv = comet.connection.createElement("div");
        comet.connection.appendChild(comet.iframediv);
        comet.connection.parentWindow.comet = comet;
        comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.php'></iframe>";
 
      } else if (navigator.appVersion.indexOf("KHTML") != -1) {
 
        // for KHTML browsers
        comet.connection = document.createElement('iframe');
        comet.connection.setAttribute('id',     'comet_iframe');
        comet.connection.setAttribute('src',    './backend.php');
        with (comet.connection.style) {
          position   = "absolute";
          left       = top   = "-100px";
          height     = width = "1px";
          visibility = "hidden";
        }
        document.body.appendChild(comet.connection);
 
      } else {
 
        // For other browser (Firefox...)
        comet.connection = document.createElement('iframe');
        comet.connection.setAttribute('id',     'comet_iframe');
        with (comet.connection.style) {
          left       = top   = "-100px";
          height     = width = "1px";
          visibility = "hidden";
          display    = 'none';
        }
        comet.iframediv = document.createElement('iframe');
        comet.iframediv.setAttribute('src', './backend.php');
        comet.connection.appendChild(comet.iframediv);
        document.body.appendChild(comet.connection);
 
      }
    },
 
    // this function will be called from backend.php  
    printServerTime: function (time) {
      $('content').innerHTML = time;
    },
 
    onUnload: function() {
      if (comet.connection) {
        comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
      }
    }
  }
  Event.observe(window, "load",   comet.initialize);
  Event.observe(window, "unload", comet.onUnload);

学习资料
Comet:基于 HTTP 长连接的“服务器推”技术
http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 

How to implement COMET with PHP
http://www.zeitoun.net/articles/comet_and_php/start

 

 

点击查看原文阅读(329) | 评论(1) | 分类:PHP

Html5 Canvas 拖拽效果 (2011-10-13)

Canvas拖拽效果


var mainCanvas;
var mainCt;
var MAIN_CANVAS_WIDTH=680;
var MAIN_CANVAS_HEIGHT=560;
var currentRectX=100;
var currentRectY=100;
var startDragRectX=0;
var startDragRectY=0;
var startDragMouseX=0;
var startDragMouseY=0;
var RECT_WIDTH=100;
var RECT_HEIGHT=100;

function pageInit(){
		mainCanvas=document.createElement("canvas");
		mainCanvas.width=MAIN_CANVAS_WIDTH;
		mainCanvas.height=MAIN_CANVAS_HEIGHT;
		document.body.appendChild(mainCanvas);
		mainCanvas.onmousedown=canvasMouseDownHandler;
		mainCanvas.onmouseup=canvasMouseUpHandler;

		mainCt=mainCanvas.getContext("2d");
		redrawRect();
}

function canvasMouseMoveHandler(event){
		var canvasMouseX=event.layerX;
		if(!canvasMouseX){
				canvasMouseX=event.x;
		}
		var canvasMouseY=event.layerY;
		if(!canvasMouseY){
				canvasMouseY=event.y;
		}

		currentRectX=startDragRectX+canvasMouseX-startDragMouseX;
		currentRectY=startDragRectY+canvasMouseY-startDragMouseY;
		redrawRect();
}

function canvasMouseUpHandler(event){
		mainCanvas.onmousemove=null;
}

function redrawRect(){
		mainCt.clearRect(0,0,MAIN_CANVAS_WIDTH,MAIN_CANVAS_HEIGHT);
		mainCt.fillStyle="#0000FF";
		mainCt.fillRect(currentRectX,currentRectY,RECT_WIDTH,RECT_HEIGHT);
}

点击查看原文阅读(345) | 评论(1) | 分类:前端开发HTML5/JS

Mysql Limit 优化,百万至千万级快速分页 复合索引 (2011-10-09)

 MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新闻的小型系统怎么写都可以,用xx框架可以实现快速开发。可是数据量到了10万,百万至千万,他的性能还能那么高吗?一点小小的失误,可能造成整个系统的改写,甚至更本系统无法正常运行!好了,不那么多废话了。用事实说话,看例子: 

数据表 collect ( id, title ,info ,vtype) 就这4个字段,其中 title 用定长,info 用text, id 是逐渐,vtype是tinyint,vtype是索引。这是一个基本的新闻系统的简单模型。现在往里面填充数据,填充10万篇新闻。 

最后collect 为 10万条记录,数据库表占用硬盘1.6G。OK ,看下面这条sql语句: 

select id,title from collect limit 1000,10; 很快;基本上0.01秒就OK,再看下面的 

select id,title from collect limit 90000,10; 从9万条开始分页,结果? 

8-9秒完成,my god 哪出问题了????其实要优化这条数据,网上找得到答案。看下面一条语句: 

select id from collect order by id limit 90000,10; 很快,0.04秒就OK。 为什么?因为用了id主键做索引当然快。网上的改法是: 

select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10; 

这就是用了id做索引的结果。可是问题复杂那么一点点,就完了。看下面的语句 

select id from collect where vtype=1 order by id limit 90000,10; 很慢,用了8-9秒! 

到了这里我相信很多人会和我一样,有崩溃感觉!vtype 做了索引了啊?怎么会慢呢?vtype做了索引是不错,你直接 select id from collect where vtype=1 limit 1000,10; 是很快的,基本上0.05秒,可是提高90倍,从9万开始,那就是0.05*90=4.5秒的速度了。和测试结果8-9秒到了一个数量级。从这里开始有人提出了分表的思路,这个和discuz 论坛是一样的思路。思路如下: 

建一个索引表: t (id,title,vtype) 并设置成定长,然后做分页,分页出结果再到 collect 里面去找info 。 是否可行呢?实验下就知道了。 

10万条记录到 t(id,title,vtype) 里,数据表大小20M左右。用 

select id from t where vtype=1 order by id limit 90000,10; 很快了。基本上0.1-0.2秒可以跑完。为什么会这样呢?我猜想是因为collect 数据太多,所以分页要跑很长的路。limit 完全和数据表的大小有关的。其实这样做还是全表扫描,只是因为数据量小,只有10万才快。OK,来个疯狂的实验,加到100万条,测试性能。 

加了10倍的数据,马上t表就到了200多M,而且是定长。还是刚才的查询语句,时间是0.1-0.2秒完成!分表性能没问题?错!因为我们的limit还是9万,所以快。给个大的,90万开始 

select id from t where vtype=1 order by id limit 900000,10; 看看结果,时间是1-2秒! 

why ?? 分表了时间还是这么长,非常之郁闷!有人说定长会提高limit的性能,开始我也以为,因为一条记录的长度是固定的,mysql 应该可以算出90万的位置才对啊? 可是我们高估了mysql 的智能,他不是商务数据库,事实证明定长和非定长对limit影响不大?怪不得有人说 discuz到了100万条记录就会很慢,我相信这是真的,这个和数据库设计有关! 

难道MySQL 无法突破100万的限制吗???到了100万的分页就真的到了极限??? 

答案是: NO !!!! 为什么突破不了100万是因为不会设计mysql造成的。下面介绍非分表法,来个疯狂的测试!一张表搞定100万记录,并且10G 数据库,如何快速分页! 

好了,我们的测试又回到 collect表,开始测试结论是: 30万数据,用分表法可行,超过30万他的速度会慢道你无法忍受!当然如果用分表+我这种方法,那是绝对完美的。但是用了我这种方法后,不用分表也可以完美解决! 

答案就是:复合索引!有一次设计mysql索引的时候,无意中发现索引名字可以任取,可以选择几个字段进来,这有什么用呢?开始的select id from collect order by id limit 90000,10; 这么快就是因为走了索引,可是如果加了where 就不走索引了。抱着试试看的想法加了 search(vtype,id) 这样的索引。然后测试 

select id from collect where vtype=1 limit 90000,10; 非常快!0.04秒完成! 

再测试: select id ,title from collect where vtype=1 limit 90000,10; 非常遗憾,8-9秒,没走search索引! 

再测试:search(id,vtype),还是select id 这个语句,也非常遗憾,0.5秒。 

综上:如果对于有where 条件,又想走索引用limit的,必须设计一个索引,将where 放第一位,limit用到的主键放第2位,而且只能select 主键! 

完美解决了分页问题了。可以快速返回id就有希望优化limit ,按这样的逻辑,百万级的limit 应该在0.0x秒就可以分完。看来mysql 语句的优化和索引时非常重要的! 

好了,回到原题,如何将上面的研究成功快速应用于开发呢?如果用复合查询,我的轻量级框架就没的用了。分页字符串还得自己写,那多麻烦?这里再看一个例子,思路就出来了: 

select * from collect where id in (9000,12,50,7000); 竟然 0秒就可以查完! 

mygod ,mysql 的索引竟然对于in语句同样有效!看来网上说in无法用索引是错误的! 

有了这个结论,就可以很简单的应用于轻量级框架了: 

代码如下: 

$db=dblink(); 
$db->pagesize=20; 

$sql="select id from collect where vtype=$vtype"; 

$db->execute($sql); 
$strpage=$db->strpage(); //将分页字符串保存在临时变量,方便输出 
while($rs=$db->fetch_array()){ 
  $strid.=$rs['id'].','; 

$strid=substr($strid,0,strlen($strid)-1); //构造出id字符串 
$db->pagesize=0; //很关键,在不注销类的情况下,将分页清空,这样只需要用一次数据库连接,不需要再开; 
$db->execute("select id,title,url,sTime,gTime,vtype,tag from collect where id in ($strid)"); 

<?php while($rs=$db->fetch_array()): ?> 
<tr> 
   <td>&nbsp;<?php echo $rs['id'];?></td> 
   <td>&nbsp;<?php echo $rs['url'];?></td> 
   <td>&nbsp;<?php echo $rs['sTime'];?></td> 
   <td>&nbsp;<?php echo $rs['gTime'];?></td> 
   <td>&nbsp;<?php echo $rs['vtype'];?></td> 
   <td>&nbsp;<a href="?act=show&id=<?php echo $rs['id'];?>" target="_blank"><?php echo $rs['title'];?></a></td> 
   <td>&nbsp;<?php echo $rs['tag'];?></td> 
</tr> 
<?php endwhile; ?> 
</table> 
<?php 
echo $strpage; 

通过简单的变换,其实思路很简单:1)通过优化索引,找出id,并拼成 "123,90000,12000" 这样的字符串。2)第2次查询找出结果。 

小小的索引+一点点的改动就使mysql 可以支持百万甚至千万级的高效分页! 

通过这里的例子,我反思了一点:对于大型系统,PHP千万不能用框架,尤其是那种连sql语句都看不到的框架!因为开始对于我的轻量级框架都差点崩溃!只适合小型应用的快速开发,对于ERP,OA,大型网站,数据层包括逻辑层的东西都不能用框架。如果程序员失去了对sql语句的把控,那项目的风险将会成几何级数增加!尤其是用mysql 的时候,mysql 一定需要专业的dba 才可以发挥他的最佳性能。一个索引所造成的性能差别可能是上千倍! 

PS: 经过实际测试,到了100万的数据,160万数据,15G表,190M索引,就算走索引,limit都得0.49秒。所以分页最好别让别人看到10万条以后的数据,要不然会很慢!就算用索引。经过这样的优化,mysql到了百万级分页是个极限!但有这样的成绩已经很不错,如果你是用sqlserver肯定卡死!而 160万的数据用 id in (str) 很快,基本还是0秒。如果这样,千万级的数据,mysql应该也很容易应付。 

点击查看原文阅读(342) | 评论(1) | 分类:数据库优化
<< 1 2 3 4 5 6 7 8 9 10 >>