Sunday, December 21, 2008

InnoDB和MyISAM的差别(mysql事务处理)

Filed under: Mysql |

Posted on 1月 13th, 2008 由 Darren

InnoDB 和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而 InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

MyIASM是IASM表的新版本,有如下扩展:
二进制层次的可移植性。
NULL列索引。
对变长行比ISAM表有更少的碎片。
支持大文件。
更好的索引压缩。
更好的键吗统计分布。
更好和更快的auto_increment处理。

1.MySQL最大的优势在于MyISAM引擎下的简单SELECT,INSERT和UPDATE快速操作
2.MyISAM类型的数据文件可以在不同操作系统中COPY,这点很重要,布署的时候方便点。

以下是一些细节和具体实现的差别:

1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

以暂对存储引擎的认识,觉得 InnoDB 支持外键,在数据量可以用“庞大”来形容时,在有良好的 INDEX 的基础上,InnoDB 的查询速度应该比 MyISAM 要快。
在 Falcon 有稳定版本前,我想 MyISAM 是一个可用的选择方案。

任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。

Tuesday, December 16, 2008

PHP > Postal Code Distance Calculator

 

Two very simple functions that work together to calculate the distance between two different Canadian postal codes.

Alternatively you could pay $600 for a database of all Canadian postal codes with longitudes and latitudes, but I don't think that's why your reading this page. This method is easy to implement, connects to a constantly updated database, and did I mention--it's free?

How it works

The one function, "getCoord", uses Google Maps API's XML feed to fetch the longitude and latitude of each postal code, the second, "calcDistance", does some freaky math to calculate the distance in kilometers.

DON'T FORGET: You'll need to signup to use the Google Maps API at http://www.google.com/apis/maps/signup.html before you can use the getCoord function. Take the key Google gives you and store it in the constant 'KEY'.

Drawbacks

I used to use GeoCoder do the same calculations which only allowed for 100 lookups a day. Now with Google we have a 50,000 lookup limit. Which I doubt you'll ever surpass.

<?php
/**
* GETCOORD
* Uses Google Maps to resolve the coordinates of a postal code

* @param   String   $postal   Postal code to lookup
* @return  Array    Returns array with latitude and longitude
* @return  Boolean  False if an error occurred
*/
// ---- | REQUIRED GOOGLE MAPS KEY | --------
// Get yours here: http://www.google.com/apis/maps/signup.html
define('KEY', '---fill me in---');
function getCoord($postal)
{
$d = file_get_contents('http://maps.google.com/maps/geo?q=' . $postal . '&output=xml&key=' . KEY);
    if (!$d)
        return false; // Failed to open connection
$coord = new SimpleXMLElement($d);
    if ((string) $coord->Response->Status->code != '200')
        return false; // Invalid status code
list($lng, $lat) = explode(',', (string) $coord->Response->Placemark->Point->coordinates);
    return array('Lat' => (float) $lat, 'Lng' => (float) $lng); 
}
/**
* CALCDISTANCE
* Calculates the distance between to postal codes

* @param   String   $postal1   Starting postal code
* @param   String   $postal2   Ending postal code
* @return  Float    Returns distance in kilometers
* @return  Boolean  False if an error occurred
*/
function calcDistance($postal1, $postal2)
{
$dst1 = getCoord($postal1);
$dst2 = getCoord($postal2);
    if (!$dst1 or !$dst2)
        return false; // Invalid postal codes
$kms = rad2deg(acos(sin(deg2rad($dst1['Lat'])) * sin(deg2rad($dst2['Lat'])) +  
cos(deg2rad($dst1['Lat'])) * cos(deg2rad($dst2['Lat'])) * 
cos(deg2rad($dst1['Lng'] - $dst2['Lng'])))) * 60 * 1.1515 * 1.609344; 
    return $kms;
}
echo calcDistance('r3g3j6', 'r0c3e0') . ' kms'; // prints 37.... kms
?>

Saturday, December 13, 2008

加拿大信用卡的选择

在加拿大,每个银行无一例外都有信用卡业务,对於很多人来说,其实并不清楚每个信用卡的功能和不同,也不知道在何种情况下使用哪张信用卡为好,其实,信用卡不用求多,但求精和有互补性。

选择信用卡有以下关键因素:

1。有无年费

2。是否攒点或现金回扣

3。有无购物保修期延长和90天失窃保险

4。有无租车优惠和租车期保险

5。有无特色业务,如ERS(Emergency Road Service)拖车服务

6。有无旅行人身保险

以上各点均非常重要,如果不知道,也就白白放弃了自己的利益。

有年费的卡,当然包含的东西会多一点,如攒点或现金回报率高一点,保险多一点,但是,其实有太多东西是免费卡都有的,只是免费卡有这没那,而年费卡保含面广,用年费卡的前提是你必须是大款,月洒万金不足惜的那种,否则,年费都挣不回来。其实,根本在於信用卡公司在免费卡上赚的少,所以没钱买更多的保险给用户,但是,我们完全可以通过组合互补来得到,所以,笔者只推荐免费卡。

除了年费,第二重要的是有无攒点或现金回扣,此类回报卡的特点是你可以在任何地方消费,如买菜,看电影,都可在卡上得回扣。

根据经验,现金回扣更实在,而攒点的回报率普遍极低,并且换取实物时的点数不可控制,一句话,骗人的招术。合理的办法是申请一个现金回扣信用卡和该公司或商店的一个纯计点卡,如ESSO,AIR MILE,HBC 等等, 用了信用卡得了回扣后再同时用计点卡攒点, 当然,点数是少了点,但当场有现金实惠,总利益远达于记点信用卡。

对於现金回扣的信用卡,目前基本上都是“UP TO 1%”, 这其实和真正的1%回扣是有很大区别的,前者基本是要花费3000元以后才开始有1%回报。真正的零元起的回报只有三家,CANADIANTIRE 的OPTION MASTER卡(1%),CAA MASTER卡(1%)和 TD BANK 的GM卡(3%),但限制是OPTION里攒的回扣钱必须在CANADIANTIRE用,CAA MASTER卡里攒的回扣钱必须用在年费,剩下的用的地方很少,而GM卡有3%,但卡里攒的回扣钱必须只能在买GM公司车的时候用。综合而论,OPTION是最好的选择,因为CANADIANTIRE回扣高,东西多,实在没啥买的时候,换换机油,买买钓鱼证都可以。

  许多人不知道,用某类信用卡买任何东西,如电器,家具等等,信用卡自动为所买的东西延长了保修期,一般为保修期翻倍,直至最多一年,例如,这样东西原有3个月保修,那么用信用卡买就有6个月,如果原有3年保修,那么用信用卡买就有4年。这很重要,因为最后一年的损坏机率最大。伴随着保修期延长的,大多是90天失窃和全毁保险,如果你买俩新自行车,第二天给偷了,凭报案记录,信用卡会赔给你。所以你要注意你的卡有没有此保险。

  对於租车优惠和保险,很多信用卡有租车优惠,例如RBC的免年费金卡和白金卡,可以得到NATIONAL租车行的20%优惠,和其他租车行 10%优惠,TD等银行的一些信用卡都有。更重要的是,如果你的自己车保险不含租车保险的话,租车是要付每天十几块钱的保险费的,如果用此类信用卡,可以免一半,即自身保可免,对方车损保险不免。

  有些信用卡,有一些很好的选项,ERS(EMERGENCY ROADSIDE SUPPORT) 是最有意义的一个,相信很多人知道或者在用CAA的ERS,其实有一些其他MASTER 卡通过付费加入AUOT CLUB是可以得到相同或更好的服务的。TD SELECT 和OPTION 就可以,以下为比较列表:

年费- 服务次数- 回报- 公里 -特色待遇 -备注

  CAA $70--4次;--1%--5km--5%CouchTard加油,有其他联锁折扣店-- 回扣钱只能用在下一年的年费,剩下的可用地方很少,CouchTard有油加的很少,全岛41家,大多偏远,且用其他信用卡也 可得 2%,很多联锁店不用CAA卡也可以在 网下载 coupon
SELECT $40--6次--无 --20km--保险非常好
OPTION $56--3次和无限次去CanadianTire--1%--10km--一次免费换油,4张价值$15换机油券,免费补胎,在 CanadianTire买东西回扣率更高,在CanadianTire加汽油回扣率更高--回扣钱只能用在 CanadianTire,有油加的店也很少.

  最后是人身旅行保险,当然有比没有好,RBC的金卡白金卡和TD SELECT卡都达到最多50万的保险,飞机和开车的旅行均含。

所以,笔者经过比较所有银行的所有信用卡,“去伪存真” ,仔细分析后,觉得CANADIANTIRE OPTION(加上$56AUTO CLUB选项)+RBC金卡或TD SELECT+记点卡(AIR MILS,ESSO,HBC等)配合使用为最佳组合。当然,申请银行的信用卡不一定要有该银行的帐户才能申请。

Friday, December 5, 2008

Prototype and script.aculo.us终极揭秘 推荐序

推荐序

2005年对于Web开发来说是一个伟大的年份。在这一年中,有两项技术异军突起,一项是Ajax,另一项是Ruby on Rails。这两项技术的出现改变了Web开发的面貌,甚至打乱了JavaEE前进的步伐。多年以来,JavaEE设计者们为自己所设计的无所不包的复杂架构而陶醉,新的buzz word层出不穷,一出来就会得到广泛的关注,相关的图书也会热卖。辉煌的JavaEE版图中居然还有完全被忽略的死角,这是JavaEE设计者们始料不及的。事实上他们在JavaEE的架构中从来就没有考虑过浏览器端的处理能力,浏览器对于JavaEE来说是完全无智能的瘦客户端。他们这样设计情有可原,因为他们只能把设计局限在Java能够控制的区域内,在Java Applet彻底失败之后,Java能够控制的区域退守到了服务器端。毫无疑问,JavaEE取得了巨大的成功,但是这种完全基于服务器端的解决方案很难向用户提供优秀的交互体验,同时也很难实现最佳的可伸缩性(Scalability)。

Ajax是用户和市场的选择,这个由群众创造出来的buzz word时常响在JavaEE设计者的耳边,令他们非常烦躁。甚至有人喊出了"JavaEE without Ajax"的口号,和2004年Rod Johnson所提出的"J2EE without EJB"相对应。但是仔细考察这个"without Ajax",我们却发现它和"without EJB"说的并不是一个意思。"without EJB"的意思就是不使用EJB,而"without Ajax"的意思却不是不使用Ajax,而是设法将Ajax隐藏掉,使得普通的JavaEE开发者不需要学习Ajax。在这个口号的发明者所设计的JSF 框架中,内嵌了一个Ajax组件库ExtJS,看来他们还是需要Ajax的帮助的。所谓的"JavaEE without Ajax"其实是一个伪命题,只是用来吸引眼球的噱头,主要的目的是为了迎合那些讨厌Ajax、对于浏览器端脚本编程没有兴趣的JavaEE开发者。其实无论开发Web应用,还是开发B/S结构的企业应用,交互体验都是非常重要的。在交互体验越来越受到重视的今天,想要把Ajax排除在外,可以说是一件不可能的任务。

尽管Ajax开发确实很重要,但无须讳言的是Ajax开发,特别是DHTML开发至今仍然是一件很复杂的工作,必须具备专业的技能。除了高超的开发技能之外,还需要开发者对于Web可用性和交互设计具有足够的理解。这超出了Web页面设计师和制作人员的能力范围;而对于服务器端开发者来说,这些显然也不是他们的特长(他们的特长是处理业务逻辑和与数据库打交道,而不是界面开发和交互设计)。在Web页面设计师和服务器端开发者之间出现了巨大的断层,这使得高水平的Ajax开发者一下子变得炙手可热。

JavaEE设计者们简化Ajax开发的努力是可以理解的。但是我们需要讨论清楚一个问题:究竟怎样做才能真正简化Ajax开发?

在我看来,JavaEE社区简化Ajax开发的努力都不是很成功。将ExtJS嵌入到JSF框架中,确实可以实现一些简单的交互需求,但是这种做法其实阉割掉了Ajax的主要能力--直接在浏览器端处理用户的事件。JSF的事件模型是完全位于服务器端的,界面的任何改变都需要发送事件到服务器端做处理。即使引入了ExtJS,也不可能改变这一点。在Struts2/WebWork和jMaki中通过使用taglib集成Ajax组件库的做法也会令人感觉笨拙而不自然。之所以集成的效果不理想,是因为传统的JavaEE框架和Ajax组件库的核心架构设计都没有考虑到对方的需求,它们在架构设计上存在着内在的冲突,拉郎配的结果是可想而知的。这些JavaEE表现层框架集成Ajax组件库,是希望将Ajax组件库改造为JavaEE世界的顺民,服从 JavaEE框架的架构约束,但是这样做不可避免地会削弱Ajax组件库的能力。要简化Ajax开发并且充分用好Ajax技术,仅仅使用taglib来对 Ajax组件库做封装是不够的,服务器端的架构也必须加以改造,甚至需要设计出一套全新的架构,这是传统的JavaEE表现层框架无法做到的。 Google的GWT同时具有浏览器端和服务器端,似乎是一个很好的选择,但是GWT主要是为实现一类One Page的Ajax应用而设计的,它模仿的是桌面应用的交互模型,而绝大多数的Web应用是不可能采用这种交互模型的。DWR也是一个跨浏览器端和服务器端的框架,但是DWR的RPC风格的API是我所不喜欢的。RPC架构和REST架构在可伸缩性方面的差距是巨大的,Ajax应用的最佳架构是REST而不是RPC,同时REST在简化编程模型方面的效果也要比RPC更好。
要简化Ajax开发,我认为需要满足以下3个要求:

1. 由专业的DHTML开发者开发出更加全面和强大的Widget库。这部分的开发应该由专业人士来做,这样就可以把负担从普通的Web开发者身上卸掉。开源软件是开发Widget库的必由之路。

2. Ajax组件库要与服务器端框架做更加紧密的集成。服务器端框架的架构需要加以改造以适应Ajax和REST的需求,不能指望以不变应万变。

3. 简化的编程模型。这包括两个方面:a)通过与服务器端框架紧密集成,使得服务器端开发者仅仅使用服务器端编程语言就能够实现一些普通的Ajax需求;b)更加复杂的交互需求如果必须要做DHTML开发,需要大幅降低DHTML开发的难度。

当我把眼光投向了Ruby on Rails之后,包括Ajax开发在内,一切都变得容易了很多。Rails通过其RJS模板集成了两个Ajax组件库Prototype和基于 Prototype的script.aculo.us。Rails集成这两个组件库的方式显得非常自然,因为这两个组件库正是Rails和Ajax相结合的产物,它们都是由Rails的核心开发人员所开发的,充分考虑到了Rails在架构方面的需求。现在这两个组件库已经长大成人,完全可以独立应用在非 Rails环境中。Rails + Prototype/script.aculo.us满足了上述3个要求,因此是目前做Ajax开发的最佳组合。当然,上述3个要求每一个都还有很大的改进余地,但是Rails + Prototype/script.aculo.us走在了正确的道路上,前景是非常光明的。

随着Ajax技术的普及,传统的DHTML组件库恢复了生机,可以加以改造以适应新的交互需求。这些DHTML组件获得了一个时髦的新名称--Widget。我一般是将Ajax组件库分成3部分:

1. 基础库。包括:a)对于JavaScript语言的增强,为目前浏览器所支持的JavaScript 1.x版提供继承、包管理等面向对象编程所需要的支持;b)封装HTML DOM的API,提供编程模型更加简化的API。

2. Web Remoting库,通过XMLHttpRequest/IFrame/JSONP等机制与服务器交互,从服务器获取数据。

3. 丰富的Widget库,可用来实现各种交互需求,以改善用户的交互体验。

Prototype库实现了第1部分和第2部分,script.aculo.us库实现了第3部分。在这3部分中,开发工作量最大的是Widget 库。正是因为市场上对于Widget库有着巨大的需求,在2007年涌现出了大量Widget库,开源的包括script.aculo.us、Dojo、 YUI、ExtJS、Mootools、jQuery UI、Spry、Tibco GI、Qooxdoo;私有的包括ASP.NET Ajax、Dorado、Zimbra,等等,全部列举下来不下二三十个。Apple公司在这一年推出了iPhone手机,其中的Widget全部是使用 DHTML开发的,达到了交互体验的极致,同时也展示出Widget开发的美好前景。很多人说2007年是Widget年,这个说法是有道理的。到了 2008年,Google公司推出了Open Social,其核心是Google所提供的Widget开发API和Widget的部署容器。Google管这些Widget叫做Google Gadget,Gadget将Widget的开发水平推向了新的高度。

无论是基于现有的Widget开发Ajax功能,还是开发新的Widget,Prototype/script.aculo.us都是我们手中的一件利器。网上的很多投票都显示出,Prototype/script.aculo.us组合是最受欢迎的Ajax组件库。因为Prototype大受欢迎,其爱好者基于Prototype还开发了很多其他的组件库,Prototype家族成员的数量还在不断增加。很多Ajax组件库最大的问题是缺乏详尽的文档,API参考并不能代替文档。从文档的数量和质量来说,Prototype/script.aculo.us的文档在所有Ajax组件库中都是最棒的。本书的出版,为爱好者深入学习这两个组件库提供了极大的便利。本书的副标题是"You Never Know JavaScript Could Do This!",确实,正是通过这些优秀的Ajax组件库、这些勇于探索的Ajax顶尖高手们,我们才知道浏览器端脚本编程的世界原来是如此灿烂。基于 Prototype/script.aculo.us做Ajax开发是一种很愉快的体验。学习越深入,这种愉快的感觉就越强烈。那么,你还在等什么呢?

上海印客网首席架构师

2008年7月6日于上海

《JavaScript王者归来》序

       在人类漫漫的历史长河里,很难找到第二个由简单逻辑和抽象符号组合而成的,具有如此宏大信息量和丰富多彩内涵的领域。从某种意义上说,当你翻开这本书的时候,你已经踏入了一个任由你制定规则的未知世界。尽管你面对的仅仅是程序设计领域的冰山一角,但你将透过它,去领悟“道”的奥秘。在接下来的一段时间内,你会同我一起,掌握一种简单而优雅的神秘语言,学会如何将你的意志作用于它。这种语言中所蕴涵着的亘古之力,将为你开启通往神秘世界的大门……

1.1为什么选择JavaScript?

       在一些人眼里,程序设计是一件神秘而浪漫的艺术工作,对他们来说,一旦选定某种编程语言,就会像一个忠贞的信徒一样坚持用它来完成任何事情,然而我不是浪漫的艺匠,大多数人也都不是,很多时候我们学习一种新技术的唯一目的,只是为了把手中的事情做得更好。所以,当你面对一项陌生的技术时,需要问的第一个问题往往是,我为什么选择它,它对我来说,真的如我所想的那么重要吗?

好,让我们带着问题开始。

1.1.1 用户的偏好:B/S模式

       如果你坚持站在专业人员的角度,你就很难理解为什么B/S模式会那么受欢迎。如果你是一个资深的程序员,有时候你甚至会对那些B/S模式的东西有一点点反感。因为在你看来,浏览器、表单、DOM和其他一切与B/S沾边的东西,大多是行为古怪而难以驾驭的。以你的经验,你会发现实现同样的交互,用B/S来做通常会比用任何一种客户端程序来做要困难得多。

       如果你尝试站在用户的角度,你会发现为什么大多数最终用户对B/S模式却是如此的青睐。至少你不必去下载和安装一个额外的程序到你的电脑上,不必为反复执行安装程序而困扰,不必整天被新的升级补丁打断工作,不必理会注册表、磁盘空间和一切对普通用户来说有点头疼的概念。如果你的工作地点不是固定的办公室,你日常工作的PC也不是固定的一台或者两台,那么,B/S的意义对你而言或许比想象的还要大。

大多数情况下,客户更偏好使用浏览器,而不是那些看起来比较专业的软件界面,专业人员则恰恰相反。

       总之,用户的需求让B/S模式有了存在的理由,而迅速发展的互联网技术则加速了B/S应用的普及。随着一些优秀的Web应用产品出现,不但唤起了用户和业内人士对Ajax技术的关注,也令Web领域内的一个曾经被无数人忽视的脚本语言——JavaScript进入了有远见的开发人员和IT经理人的视线。于是在你的手边,也多了现在这本教程。

编写本书的时候,在TIOBE编程社区最新公布的数据中,JavaScript在世界程序开发语言中排名第十,这意味着JavaScript已经正式成为一种被广泛应用的热门语言。

1.1.2 在什么情况下用JavaScript

       一路发展到今天,JavaScript的应用范围已经大大超出一般人的想象,但是,最初的JavaScript是作为嵌入浏览器的脚本语言而存在,而它所提供的那些用以表示Web浏览器窗口及其内容的对象简单实用,功能强大,使得Web应用增色不少,以至于直到今天,在大多数人眼里,JavaScript 表现最出色的领域依然是用户的浏览器,即我们所说的Web应用的客户端。客户端浏览器的JavaScript应用也正是本书讨论的重点内容。

作为一名专业程序员,当你在面对客户的时候,经常需要判断哪些交互需求是适合于JavaScript来实现的。而作为一名程序爱好者或者是网页设计师,你也需要了解哪些能够带给人惊喜的特效是能够由JavaScript来实现的。总之一句话,除了掌握JavaScript本身,我们需要学会的另一项重要技能是,在正确的时候、正确的地方使用JavaScript。对于JavaScript初学者来说学会判断正确使用的时机有时候甚至比学会语言本身更加困难。

作为项目经理,我经常接受来自客户的抱怨。因此我很清楚我们的JavaScript在带给客户好处的同时制造了太多的麻烦,相当多的灾难是由被错误使用的 JavaScript引起的。一些代码本不应该出现在那个位置,而另一些代码则根本就不应当出现。我曾经寻访过问题的根源,发现一个主要的原因由于 JavaScript的过于强大(在后面的小节中我们将会提到,另一个同样重要的原因是“脚本诱惑”),甚至超越了浏览器的制约范围,于是麻烦就不可避免的产生了,这就像你将一个魔鬼放入一个根本就不可能关住它的盒子里,那么你也就无法预料魔鬼会做出任何超出预期的举动。

*  毫无疑问,正确的做法是:不要放出魔鬼。所以,JavaScript程序员需要学会的第一个技巧就是掌握在什么情况下使用JavaScript才是安全的。

       在什么情况下用JavaScript?给出一个简单的答案是:在任何不得不用的场合使用,除此以外,不要在任何场合使用!无懈可击的应用是不用,除非你确实无法找到一个更有效更安全的替代方案。也许这个答案会让读到这里的读者有些郁闷,但是,我要很严肃地提醒各位,由于JavaScript比大多数人想象的要复杂和强大得多,所以它也比大多数人想象得要危险得多。在我的朋友圈子里,许多资深的JavaScript程序员(包括我在内)偶尔也不得不为自己一时疏忽而做出的错误决定让整个项目团队在“脚本泥潭”中挣扎好一阵子。所以这个建议从某种意义上说也是专家们的血泪教训。最后向大家陈述一个令人欣慰的事实,即使是像前面所说的这样,在Web应用领域,JavaScript的应用范围也仍然是相当广泛的。

Ø         在本节的最后三个小节里,我们将进一步展开讨论关于JavaScript使用的话题。

1.1.3 对JavaScript的一些误解

       JavaScript是一个相当容易误解和混淆的主题,因此在对它进一步研究之前,有必要澄清一些长期存在的有关该语言的误解。

1.1.3.1 JavaScript和Java

这是最容易引起误会的一个地方,这个Java-前缀似乎暗示了JavaScript和Java的关系,也就是JavaScript是Java的一个子集。看上去这个名称就故意制造混乱,然后随之而来的是误解。事实上,这两种语言是完全不相干的。

JavaScript和Java的语法很相似,就像Java和C的语法相似一样。但它不是Java的子集就像Java也不是C的子集一样。在应用上,Java要远比原先设想的好得多(Java原称Oak)。

JavaScript 的创造者是Brendan Eich,最早的版本在NetScape 2中实现。在编写本书时,Brendan Eich在Mozilla公司任职,他本人也是JavaScript的主要革新者。而更加有名的Java语言,则是出自Sun Microsystems公司的杰作。

JavaScript最初叫做LiveScript,这个名字本来并不是那样容易混淆,只是到最后才被改名为JavaScript,据说起同Java相似的名字纯粹是一种行销策略。

尽管JavaScript和Java完全不相干,但是事实上从某种程度上说它们是很好的搭档。JavaScript可以控制浏览器的行为和内容,但是却不能绘图和执行连接(这一点事实上并不是绝对的,通过模拟是可以做到的)。而Java虽然不能在总体上控制浏览器,但是却可以绘图、执行连接和多线程。客户端的JavaScript可以和嵌入网页的Java applet 进行交互,并且能够对它执行控制,从这一意义上来说,JavaScript真的可以脚本化Java。

1.1.3.2披着C外衣的Lisp

JavaScript的C风格的语法,包括大括号和复杂的for 语句,让它看起来好像是一个普通的过程式语言。这是一个误导,因为JavaScript和函数式语言如Lisp和Scheme有更多的共同之处。它用数组代替了列表,用对象代替了属性列表。函数是第一型的。而且有闭包。你不需要平衡那些括号就可以用λ算子。

Ø         关于JavaScript闭包和函数式的内容,在本书的第23章中会有更详细的介绍。

1.1.3.3思维定势

JavaScript 是原被设计在Netscape Navigator 中运行的。它的成功让它成为几乎所有浏览器的标准配置。这导致了思维定势。认为JavaScript是依赖于浏览器的脚本语言。其实,这也是一个误解。 JavaScript也适合很多和Web无关的应用程序。

早些年在学校的时候,我和我的实验室搭档曾经研究过将JavaScript作为一种PDA控制芯片的动态脚本语言的可行性,而在我们查阅资料的过程中发现一些对基于嵌入式环境的动态脚本语言实现的尝试,我们有理由相信,JavaScript在某些特定的嵌入式应用领域中也能够表现得相当出色。

1.1.3.4业余爱好者

一个很糟糕的认知是:JavaScript过于简朴,以至于大部分写JavaScript的人都不是专业程序员。他们缺乏写好程序的修养。JavaScript有如此丰富的表达能力,他们可以任意用它来写代码,以任何形式。

事实上,上面这个认知是曾经的现实,不断提升的Web应用要求和Ajax彻底改变了这个现实。通过学习本书,你也会发现,掌握JavaScript依然需要相当高的专业程序员技巧,而不是一件非常简单的事情。不过这个曾经的现实却给JavaScript带来了一个坏名声──它是专门为外行设计的,不适合专业的程序员。这显然是另一个误解。

推广JavaScript最大的困难就在于消除专业程序员对它的偏见,在我的项目团队中许多有经验的J2EE程序员却对JavaScript停留在一知半解甚至茫然的境地,他/她们不愿意去学习和掌握JavaScript,认为这门脚本语言是和浏览器打交道的美工们该干的活儿,不是正经程序员需要掌握的技能。这对于Web应用开发来说,无疑是一个相当不利的因素。

1.1.3.5面向对象

JavaScript 是不是面向对象的?它拥有对象,可以包含数据和处理数据的方法。对象可以包含其它对象。它没有类(在JavaScript 2.0真正实现之前),但它却有构造器可以做类能做的事,包括扮演类变量和方法的容器的角色。它没有基于类的继承,但它有基于原型的继承。两个建立对象系统的方法是通过继承和通过聚合。JavaScript两个都有,但它的动态性质让它可以在聚合上超越。

一些批评说JavaScript不是真正面向对象的因为它不能提供信息的隐藏。也就是,对象不能有私有变量和私有方法:所有的成员都是公共的。但随后有人证明了JavaScript对象可以拥有私有变量和私有方法。另外还有批评说JavaScript不能提供继承,但随后有人证明了JavaScript不仅能支持传统的继承还能应用其它的代码复用模式。

说 JavaScript是一种基于对象的语言,是一种正确而略显保守的判断,而说JavaScript不面向对象,在我看来则是错误的认知。事实上有充足的理由证明JavaScript是一种的面向对象的语言,只是与传统的class-based OO(基于类的面向对象)相比,JavaScript有它与众不同的地方,这种独特性我们称它为prototype-based OO(基于原型的面向对象)。

Ø         关于JavaScript面向对象的内容,在本书的第21章中会有更详细的介绍。

1.1.3.6其他误解

       除了以上提到的几点之外,JavaScript还有许多容易令人迷惑和误解的特性,这些特性使得JavaScript成为世界上最被误解的编程语言。

Ø         如果读者对这方面有兴趣,可以详细阅读下面这篇文章

http://javascript.crockford.com/javascript.html  [Douglas Crockford]

1.1.4 警惕!脚本诱惑

       前面我们提到过,许多专业程序员拒绝去了解如何正确使用JavaScript,另一些则是缺乏对JavaScript足够的认知和应用经验。但是在B/S 应用中,相当多的情况下,要求开发人员不得不采用JavaScript。于是,一个问题产生了,大量的JavaScript代码拷贝出现在页面的这个或者那个地方,其中的大部分是不必要的,另一部分可能有缺陷。我们的开人员没有办法(也没有意识到)去判断这些代码是否必要,以及使用它们会带来哪些问题。

*  如果你的B/S应用中的JavaScript不是由专业的JavaScript程序员来维护的,那么当你对你的开发团队进行一次小小的代码走查时,你甚至可能会发现90%的JavaScript代码被错误地使用,这些错误使用的代码浪费了用户大量的网络带宽、内存和CPU资源,提升了对客户端配置的要求,降低了系统的稳定性,甚至导致许多本来可以避免的安全问题。

       由于浏览器的JavaScript可以方便地被复制粘贴,因此,一个特效或者交互方式往往在真正评估它的必要性之前便被采用——客户想要它,有人使用过它,程序员复制它,而它就出现在那儿,表面上看起来很完美,于是,所谓的脚本诱惑就产生了。

       事实上,在我们真正使用JavaScript之前,需要反复问自己一个重要问题是,究竟是因为有人想要它,还是因为真正有人需要它。在你驾驭 JavaScript马车之前,你必须学会抵制脚本诱惑,把你的脚本用在必要的地方,永远保持你的Web界面简洁,风格一致。

*  在用户眼里,简洁一致的风格与提供强大而不常用的功能和看起来很COOL而实际上没有什么功用的界面特效相比起来,前者更能令他们觉得专业。毕竟,大部分用户和你我一样,掌握一个陌生的环境和新的技能只是为了能够将事情做得更快更好。除非你要提供的是一个类似于Qzone之类的娱乐程序,你永远也不要大量地使用不必要的JavaScript。

1.1.5 隐藏在简单表象下的复杂度

       专业人员不重视JavaScript的一个重要原因是,他们觉得JavaScript是如此的简单,以至于不愿意花精力去学习(或者认为不用学习就能掌握)。前面提到过的,这实际上是一种误解。事实上,在脚本语言中,JavaScript属于相当复杂的一门语言,它的复杂程度未必逊色于Perl和 Python。

另一个业内的偏见是脚本语言都是比较简单的,实际上,一门语言是否脚本语言往往是它的设计目标决定的,简单与复杂并不是区分脚本语言和非脚本语言的标准。JavaScript即使放到非脚本语言中来衡量,也是一门相当复杂的语言。

       之所以很多人觉得JavaScript过于简单,是因为他们大量使用的是一些JavaScript中看似简单的文法,解决的是一些看似简单的问题,真正复杂而又适合JavaScript的领域却很少有人选择JavaScript,真正强大的用法很少被涉及。JavaScript复杂的本质被一个个简单应用的表象所隐藏。

       我曾经给一些坚持认为JavaScript过于简单的开发人员写过一段小代码,结果令他们中的大部分内行人大惊失色,那段代码看起来大致像下面这个样子:

var a = [-1,-1,1,-3,-3,-3,2,2,-2,-2,3,-1,-1];

function f(s, e)

{

       var ret = [];

       for(var i in s){

              ret.push(e(s[i]));

       }

       return ret;

}

var b = f(a, function(n){return n>0?n:0});

alert(b);

*  这是本书中出现的第一段JavaScript代码,也许现在你看来,它有那么一点点令人迷惑,但是不要紧,在本书后面的章节中,你会慢慢理解这段代码的含义以及它的无穷妙味。而现在你完全可以跳过它的实际内容,只要需要知道这是一段外表看起来简单的魔法代码就够了。

       因为这段代码而尖叫的不仅仅包括我的这些程序员朋友,事实上,更兴奋的是另一些电子领域的朋友,他们写信给我反馈说,在此之前他们从来没有见到过如此形式简洁而优雅的数字高通滤波器,更令人欣喜的是,它的阈值甚至是可调节的:

var b = f(a, function(n){return n>=-1?n:0});

如果你想要,它也很容易支持低通滤波:     

var b = f(a, function(n){return n<0?n:0});

       用一个小小的堆栈或者其他伎俩,你也可以构造出一族差分或者其他更为复杂的数字设备,而它们明显形式相近并且结构优雅。

       总之,不要被简单的表象所迷惑,JavaScript的复杂度往往很大程度上取决于你的设计思路和你的使用技巧。JavaScript的确是一门可以被复杂使用的程序设计语言。

1.1.6 令人迷惑的选择:锦上添花还是雪中送炭

       本节最后的这个话题在前面已经被隐讳地提到过多次,实际上,本小节围绕的话题依然是什么时候使用JavaScript。一种比较极端的观点是在必须的时候采用,也就是前面所说的不得不用的场合,另一种比较温和一点的观点则坚持在需要的时候使用,这种观点认为当我们可以依靠JavaScript令事情变得更好的时候,我们就采用它。

事实上,就我个人而言,比较支持“必须论”,这是因为从我以往的经验来看,JavaScript是难以驾驭的,太多的问题由使用JavaScript不当而产生,其中的一部分相当令人困扰,彻底解决它们的办法就是尽可能降低JavaScript的使用频率,也尽可能将它用在真正适合它的地方。当然万事没有绝对,在何时使用 JavaScript永远是一个难题,然而不管怎么说同“锦上添花”相比,JavaScript程序员也许应当更多考虑的是如何“雪中送炭”。

1.1.7回到问题上来

       本节要解决的问题是为什么选择JavaScript,然而在相当多的篇幅里,我们都在试图寻找一些少用和不用JavaScript的理由,尽管如此,抛开大部分不适合JavaScript的位置和时机,浏览器上依然会经常地见到JavaScript的身影,对于浏览器来说,JavaScript实在是一个不可缺少的修饰。

你再也找不到任何一种优雅简朴的脚本语言如此适合于在浏览器中生存。在本书的第2章,我们将具体接触嵌入浏览器中的JavaScript。

       最后,用一句话小结本节的内容——我们之所以选择JavaScript,是因为:Web应用需要JavaScript,我们的浏览器、我们的程序员和我们的用户离不开它。

为什么Applet不会回来

我想知道为什么Javascript能够战胜Applet,找到了如下答案:

From: http://www.javaeye.com/topic/208508

     在上个世纪90年代,sun和微软的关系曾经十分甜蜜,当时的applet也是前景一片光明。然而随后sun选择了挑战微软,除了指控微软向java添加非平台中立的特性以外,在Java1.2中,sun加入了平台无关的UI界面Swing.而也正是从java1.2开始,这个星球上最大的浏览器厂商决定对Java applet进行抵制,微软的jvm版本再没有超过1.1。而java1.2之后sun的jvm在ie上的拙劣表现,也最终导致applet的陨落。

      来到21世纪,sun想要通过新的java 6 update 10和JavaFX重夺RIA市场。然而这样的尝试最终也会失败,这与applet,flash,silverlight这些技术无关,applet终将失败的原因是:sun不是一个足够强大的公司,而这一点是毫无悬念的。

Ted Neward 的话,我觉得有一定道理,但是,基于很多原因(真的有很多),我认为Applet(JavaFX)还是有机会的。当然因为我本身对Java很有感情,所以也许主观了吧。

Thursday, December 4, 2008

cakephp+AJAX打造多级动态树形菜单~~

说是用cakephp,其实也没用到cakephp的ajax helper,只是喜欢cakephp的MVC和ORM功能~

敏捷开发日益被人关注~比起JAVA的struts、hibernate无比复杂的配置文件,cakephp的mvc和orm功能仅需要满足它的一些约定就行了~就像RoR的“约定大于配置”一样~

都说ajax是过渡时期的产品,我觉得很奇怪,ajax不就只是一个XMLHttpRequest么?难道JAVASCRIPT对DOM的操作也属于AJAX?如果是这样的话AJAX怎么会只是过渡时期的产品?

不说废话了,来看看我们的AJAX+CAKEPHP多级动态树形菜单吧~~

先建立数据库表,mysql下

DROP TABLE IF EXISTS `categorys`;
CREATE TABLE IF NOT EXISTS `categorys` (
`id` int(10) unsigned NOT NULL auto_increment,//主键
`parentid` int(10) unsigned NOT NULL,//树形菜单,父结点ID号
`path` varchar(200) NOT NULL,//访问路径
`ordernum` int(11) NOT NULL,//排序号,可能用得上
`subscount` int(10) unsigned NOT NULL,//子结点个数
`name` varchar(15) NOT NULL,//结点名字
`contentable` tinyint(1) NOT NULL,//该结点下是否有非结点内容标记
`workable` tinyint(1) NOT NULL,//该结点是否工作标记
PRIMARY KEY  (`id`),
UNIQUE KEY `path` (`path`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM  DEFAULT CHARSET=gbk AUTO_INCREMENT=53 ;

将树形菜单存放数据按上面字段注释的要求填入~

下面这个是前台代码:

<script src=”../js/prototype.js”></script>
<script type=”text/javascript”>
var childNodeId;
var childValue;
function gettype(nodeId,nodeValue){
childNodeId = nodeId;
childValue = nodeValue;
var temp;
temp=$(”node”+nodeValue+”"+nodeId).innerHTML;
if (temp==”"){
$(”node”+nodeValue+”"+nodeId).innerHTML=”<span align=\”center\”><img src=’../img/common/tree/load.gif’ />    数据读取中…</span><br>”;
getChildTree();
}
else {
showHide();
}
}

function getChildTree(){
var url = “/admin/listcates/”+childNodeId+”?timestamp=”+new Date().getTime();

var myAjax = new Ajax.Request(
url,{
method:”GET”,
onComplete: showResponse
}
);
}

function showResponse(xmlHttp){
var tmp = “node”+childValue+”"+childNodeId;
var tmpimg = “img”+childValue+”"+childNodeId;
$(tmp).innerHTML = xmlHttp.responseText;
$(tmpimg).src = “../img/common/tree/open.gif”;
}

function showHide(){
var tmp = “node”+childValue+”"+childNodeId;
var tmpimg = “img”+childValue+”"+childNodeId;
if($(tmp).style.display==”block” || $(tmp).style.display==”"){
$(tmp).style.display = “none”;
$(tmpimg).src=”../img/common/tree/close.gif”;
}
else{
$(tmp).style.display =”block”;
$(tmpimg).src=”../img/common/tree/open.gif”;
}
}

function addsubject(parentid){
var tmpvalue=prompt(’请输入新的分类名’,”);
if(tmpvalue){
var url = “/admin/newsubject/”+tmpvalue;
var pars = “parentid=”+parentid+”&timestamp=”+new Date().getTime();
var ajax = new Ajax.Request(
url,{
method: ‘get’,
parameters: pars,
onComplete:viewadd
}
);
}
}
function viewadd(xmlHttp){
alert(xmlHttp.responseText);
}

function delsubject(parentid){
var tmpvalue=confirm(’确定删除这个分类吗?’);
if(tmpvalue){
alert(parentid);
}
}
</script>
<table>
<div id=”treebody”>
<span id=”node00″></span>
<script language=”javascript”>gettype(0,0)</script>
</div>
</table>

后台主要代码如下:

function listcates($parentid){
$condition = array(’parentid’=>$parentid);
$db_cates = $this->Cate->findAll($condition);
//pr($db_cates);
header(’Content-Type:text/html;charset=GB2312′);
//$parentid+=1;
if($db_cates != null){
echo “<ul style=’list-style-type:none;’>”;
foreach($db_cates as $key=>$db_cate){
if($db_cate['Cate']['subscount']!=0){
$tmpimg = “/img/common/tree/close.gif”;
echo ”
<li onclick=’gettype({$db_cate['Cate']['id']},{$parentid})’>
<img id=’img{$parentid}{$db_cate['Cate']['id']}’ src=’{$tmpimg}’ />&nbsp;{$db_cate['Cate']['name']}

</li>
<div id=’node{$parentid}{$db_cate['Cate']['id']}’></div>
“;
}
else{
$tmpimg = “/img/common/tree/file.gif”;
echo ”
<li>
<img id=’img{$parentid}{$db_cate['Cate']['id']}’ src=’{$tmpimg}’ />&nbsp;{$db_cate['Cate']['name']}
&nbsp;<img src=’/img/common/tree/new.gif’ onclick=’addsubject({$db_cate['Cate']['id']})’/>
&nbsp;<img src=’/img/common/tree/del.gif’ onclick=’delsubject({$db_cate['Cate']['id']})’/>
</li>

“;
}
}
if($parentid!=0) echo “<li onclick=’addsubject({$parentid})’><img src=’/img/common/tree/add.gif’/>&nbsp;<small>增加分类< /small></li>”;
echo “</ul>”;
}
exit();
}