Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15845 articles
Browse latest View live

JdbcTemplate学习笔记

$
0
0

1、使用JdbcTemplate的execute()方法执行SQL语句

  1. jdbcTemplate.execute("CREATE TABLE USER (user_id integer, name varchar(100))");  

2、如果是UPDATE或INSERT,用update()方法。

  1. jdbcTemplate.update("INSERT INTO USER VALUES('"  
  2.            + user.getId() + "', '"  
  3.            + user.getName() + "', '"  
  4.            + user.getSex() + "', '"  
  5.            + user.getAge() + "')");  


3、带参数的更新

 
  1. jdbcTemplate.update("UPDATE USER SET name = ? WHERE user_id = ?", new Object[] {name, id});  
 
  1. jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)", new Object[] {user.getId(), user.getName(), user.getSex(), user.getAge()});  


4、使用JdbcTemplate进行查询时,使用queryForXXX()等方法 int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM USER");  String name = (String) jdbcTemplate.queryForObject("SELECT name FROM USER WHERE user_id = ?", new Object[] {id}, java.lang.String.class);  

  1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");
  2. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");  
  3. Iterator it = rows.iterator();  
  4. while(it.hasNext()) {  
  5.     Map userMap = (Map) it.next();  
  6.     System.out.print(userMap.get("user_id") + "\t");  
  7.     System.out.print(userMap.get("name") + "\t");  
  8.     System.out.print(userMap.get("sex") + "\t");  
  9.     System.out.println(userMap.get("age") + "\t");  
  10. }  

   JdbcTemplate将我们使用的JDBC的流程封装起来,包括了异常的捕捉、SQL的执行、查询结果的转换等等。spring大量使用Template Method模式来封装固定流程的动作,XXXTemplate等类别都是基于这种方式的实现。
    除了大量使用Template Method来封装一些底层的操作细节,spring也大量使用callback方式类回调相关类别的方法以提供JDBC相关类别的功能,使传统的JDBC的使用者也能清楚了解spring所提供的相关封装类别方法的使用。

JDBC的PreparedStatement

 
final String id = user.getId();
final String name = user.getName(); 
final String sex = user.getSex() + "";
final int age = user.getAge();
jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)",                       new PreparedStatementSetter() {                           public void setValues(PreparedStatement ps) throws SQLException {                               ps.setString(1, id);
ps.setString(2, name); 
ps.setString(3, sex);
ps.setInt(4, age);  
        }
  });  
 
  1. final User user = new User();  
  2. jdbcTemplate.query("SELECT * FROM USER WHERE user_id = ?",  
  3.                     new Object[] {id},  
  4.                     new RowCallbackHandler() {  
  5.                         public void processRow(ResultSet rs) throws SQLException {  
  6.                             user.setId(rs.getString("user_id"));  
  7.                             user.setName(rs.getString("name"));  
  8.                             user.setSex(rs.getString("sex").charAt(0));  
  9.                             user.setAge(rs.getInt("age"));  
  10.                         }  
  11.                     });  
 
  1. class UserRowMapper implements RowMapper {  
  2.     public Object mapRow(ResultSet rs, int index) throws SQLException {  
  3.         User user = new User();  
  4.   
  5.         user.setId(rs.getString("user_id"));  
  6.         user.setName(rs.getString("name"));  
  7.         user.setSex(rs.getString("sex").charAt(0));  
  8.         user.setAge(rs.getInt("age"));  
  9.   
  10.         return user;  
  11.     }  
  12. }  
  13.   
  14. public List findAllByRowMapperResultReader() {  
  15.     String sql = "SELECT * FROM USER";  
  16.     return jdbcTemplate.query(sql, new RowMapperResultReader(new UserRowMapper()));  
  17. }  

在getUser(id)里面使用UserRowMapper

 
  1. public User getUser(final String id) throws DataAccessException {  
  2.     String sql = "SELECT * FROM USER WHERE user_id=?";  
  3.     final Object[] params = new Object[] { id };  
  4.     List list = jdbcTemplate.query(sql, params, new RowMapperResultReader(new UserRowMapper()));  
  5.   
  6.     return (User) list.get(0);  
  7. }  

网上收集
org.springframework.jdbc.core.PreparedStatementCreator 返回预编译SQL   不能于Object[]一起用

 
  1. public PreparedStatement createPreparedStatement(Connection con) throws SQLException {  
  2.  return con.prepareStatement(sql);  
  3. 增删改

org.springframework.jdbc.core.JdbcTemplate   类(必须指定数据源dataSource)

 
  1. template.update("insert into web_person values(?,?,?)",Object[]);
 
  1. template.update("insert into web_person values(?,?,?)",new PreparedStatementSetter(){ 匿名内部类 只能访问外部最终局部变量  
  2.   
  3.  public void setValues(PreparedStatement ps) throws SQLException {  
  4.   ps.setInt(index++,3);  
  5. });  


org.springframework.jdbc.core.PreparedStatementSetter 接口 处理预编译SQL

 
  1. public void setValues(PreparedStatement ps) throws SQLException {  
  2.  ps.setInt(index++,3);  
  3. }  


2.查询JdbcTemplate.query(String,[Object[]/PreparedStatementSetter],RowMapper/RowCallbackHandler)
org.springframework.jdbc.core.RowMapper   记录映射接口  处理结果集

 
  1. public Object mapRow(ResultSet rs, int arg1) throws SQLException {   int表当前行数  
  2.   person.setId(rs.getInt("id"));  
  3. }  
  4. List template.query("select * from web_person where id=?",Object[],RowMapper);  


org.springframework.jdbc.core.RowCallbackHandler  记录回调管理器接口 处理结果集

 
  1. template.query("select * from web_person where id=?",Object[],new RowCallbackHandler(){  
  2.  public void processRow(ResultSet rs) throws SQLException {  
  3.   person.setId(rs.getInt("id"));  
  4. });


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




谷歌Android Silver计划曝光 进入高端市场是福是祸?

$
0
0

谷歌Nexus系列早已变了味。当初谷歌想将其定义为Android阵营的硬件标杆,但为了不与众OEM厂商争夺市场,转而开始主打性价比。然而随着三星在全球Android市场独树一帜,Nexus正变得越来越边缘化。是保留还是剔除?谷歌需要做出决定。

全球分辨率最高7寸平板来袭 全新Nexus 7试玩

如今网传谷歌将放弃Nexus品牌,用“Android Silver”计划取而代之。简单地说,Android Silver与现今的Google Play Edition品牌非常相似。谷歌预计耗资10亿美元打造该项目,具体内容是与手机厂商、运营商合作开发高端Android机型并配以最纯净的Android系统,限制第三方应用与服务。同时谷歌还将承担包括广告在内的宣传费用,销售渠道由谷歌直接控制。

这意味着Android Silver可能并不像之前Nexus代工方式那么简单,谷歌将直接参与手机的研发工作。相比Nexus,Android Silver是谷歌在移动硬件领域更进一步的尝试,而它的目的可能有二:

南极最强手机:将Nexus 4放入冰箱跑分 成绩大幅提升

第一,谷歌希望改变消费者对Android的传统观念。作为Android亲儿子,Nexus逐渐沦为性价比的象征,这是谷歌所不愿意看到的。为了让更多iPhone用户转投Android阵营,为了吸引更多优秀的开发者,Android是时候改变其平庸的形象。与其让OEM厂商在高端领域打个你死我活,不如由谷歌自己掌控Android高端定义的标准,毕竟它才是Android的核心。

第二,谷歌希望统一Android的系统体验。Android机的界面交互实在是太繁太乱,靠Nexus去推广统一标准已然失败。于是谷歌抓住了最有典型性的高端市场,试图以一种高端机应有的姿态自上而下地进行渗透。它想告诉消费者的是:高端Android就应该像Silver这样,其他都是歪门邪道。

显然,谷歌不会再以实惠的价格来定义Android Silver。据悉Android Silver将首先瞄准美国和其他发达市场,但这样一来谷歌面临一个问题,它准备好与众OEM厂商进行正面冲突了吗?高端机是品牌的象征,对谷歌如此,对其他厂商亦是如此。无论如何谷歌贸然推出Android Silver,将会是场腥风血雨。

java 内存移到堆外!!! Jvm gcih 淘宝优化JVM实践

$
0
0

官方地址

Jvm gcih

出自Jvm  GC-Invisible Heap

什么是GCIH

GC-Invisible Heap,简称GCIH,是一种将Java对象从Java堆内移动到堆外,并且可以在JVM间共享这些对象的技术。

为什么要用GCIH

 GCIH顾名思义就是GC访问不到的堆,它是对JVM内存管理机制的一个有益的补充。
 在某些特殊的应用中有大量生命周期很长的对象,在应用运行的整个过程中它们都存在,不需要被GC回收。如果这类对象很多,总体占用内存比例高,那么他们的存在将给GC带来很多不必要的工作负担。例如在淘宝的很多应用中都具有大量的Forest对象,目前这些对象已经占用超过400MB,它们本身在应用提供服务前创建,在服务过程中永远存在。那么实际在GC的收集工作中针对这些对象的所有访问、操作其实都是“无用功”。如果我们把这些对象 从Java堆内移动到堆外,那么这些对象所占用的Java堆内空间将被释放,GC的工作量将会降低,从而每次full GC的时间将会缩短。
 除此以外,目前JVM间没有很高效的内存/对象共享技术,GCIH为在JVM间共享内存/对象提供了必要的基础。通过这种技术可以将那些移动到GCIH内对象在JVM间共享,从而减少内存的总体占用。

GCIH + Hesper + Forest线上测试结果对比

下面的性能测试数据来自于线上gcih + hesper + forest的实际压测数据,具体结论由淘宝性能测试团队统计。

  • 系统load对比
在相同的tps下,采用gcih的hesper响应时间明显要比不采用gcih的hesper的响应时间要低。随着压力的不断增加,tps超过55后,非gcih的hesper响应时间明显上升速度加快,当tps上升至72后,响应时间直接飙至200ms以上。而采用gcih的响应时间上升速度则相对于平缓。
  • 机器资源消耗对比
在tps处于20~50之间时,gcih的load要略低于非gcih。在tps超过55后,非gcih的load出现急速上升。 在tps相同的情况下,gcih的cpu消耗约降低20%~30%.
  • 单机最大能力对比
当load达到5~6之间、且RT<200ms的情况下,hesper(非gcih)的tps约为46~55左右,hesper(gcih)的tps值约为60~68左右。此时,hesper(非gcih)的单机能力比hesper(gcih)提升20%;
 当load<15,cpu使用率<85%的情况下,hesper(非gcih)的最大单机能力为tps:68~70,hesper(gcih)的tps值约为88左右。此时计算,采用gcih的hesper应用单机最大能力可提升25%。
  • 综上:gcih的性能明显优于非gcih,可以使单机能力提升20%左右。


GCIH内存共享

有关GCIH内存共享

GCIH 内存共享有以下特点:

  • 不经过JNI调用
  • 没有序列化和反序列化
  • GC性能提高
  • 数据更集中,cache命中率提高

GCIH内存共享与Hadoop

  • Map/Reduce 有时需要一些公用的对象,每个client JVM都有一份拷贝。
  • 一旦初始化好,在使用过程中是只读的
  • 对象比较大,占用较多内存,甚至成为瓶颈
  • 一个实际场景,dump中心的UDP,用来做join的一些公共Hashmap共享后可以节约内存,甚至可能提高效率(如果内存是瓶颈)

下图显示了使用GCIH内存共享功能后的Hadoop系统状况,左边的图表示使用GCIH前系统内每个JVM进程内均有一份对象的拷贝, 右边的图显示使用GCIH后多个JVM进程共享一份数据,有效降低了物理内存的使用。 


官方地址


官方地址

官方地址

作者:kkgbn 发表于2014-4-30 16:54:51 原文链接
阅读:71 评论:0 查看评论

用JavaScript将Canvas内容转化成图片的方法

$
0
0

上周我们花了半天时间开发下一个准备放进Mozilla Marketplace的应用。有一个应用现在非常的火热,那就是Instagram,Facebook花了100万美元收购了它。我们也想有100万美元装到口袋里,我决定开发一个Instagram风格的应用,这篇文章了我将介绍一下如何将一张图片拷贝到canvas里,以及反过来,如何将画布内容保存成图片格式。

使用JavaScript将图片拷贝进画布

要想将图片放入画布里,我们使用canvas元素的 drawImage方法:

// Converts image to canvas; returns new canvas element
function convertImageToCanvas(image) {
	var canvas = document.createElement("canvas");
	canvas.width = image.width;
	canvas.height = image.height;
	canvas.getContext("2d").drawImage(image, 0, 0);

	return canvas;
}

这里的 0, 0参数画布上的坐标点,图片将会拷贝到这个地方。

用JavaScript将画布保持成图片格式

如果你的画布上的作品已经完成,你可以用下面简单的方法将canvas数据转换成图片格式:

// Converts canvas to an image
function convertCanvasToImage(canvas) {
	var image = new Image();
	image.src = canvas.toDataURL("image/png");
	return image;
}

这段代码就能神奇的将canvas转变成PNG格式!

这些在图片和画布之间转换的技术可能比你想象的要简单的多。在以后的文章里,我会写一些将这些图片做不同滤镜处理的技术。

Google移动网站设计原则

$
0
0


Google刚刚 发布了由Google与AnswerLab联合打造,名为《Principles of Mobile Site Design: Delight Users and Drive Conversions》的移动网站设计原则白皮书。白皮书提到,为了愉悦用户和推动转化率,移动网站设计应该遵循25个设计原则。

这25个设计原则涉及到主页与网站导航、网站搜索、商务与会话、表单项、可用性等5个设计领域,包括:

主页与网站导航

01、要求动作居前居中

02、菜单务必简洁明了

03、返回主页应当容易

04、促销不能喧宾夺主

网站搜索

05、网站搜索应易发现

06、确保搜索结果相关

07、过滤改善搜索结果

08、引导用户改善结果

商务与会话

09、提交前让用户探索页面

10、访客身份也能购买东西

11、利用已有信息提供便利

12、利用点击呼叫做复杂事

13、完成跨设备转换要方便

表单项

14、信息输入要求精简流畅

15、选择最简单的输入方式

16、用可视化日历输入日期

17、用标签与实时验证除错

18、设计高效表单

可用性

19、针对移动优化整站

20、别让用户缩放网站

21、产品图片应可扩展

22、指出最佳浏览方向

23、保持单个浏览窗口

24、不要放“全站”标签

25、获取位置需说理由

这些最佳实践指导应该对设计出优秀的移动网站大有裨益,感兴趣者可到 此处下载白皮书。

除非注明,本站文章均为原创或编译,转载请注明: 文章来自 36氪

36氪官方iOS应用正式上线,支持『一键下载36氪报道的移动App』和『离线阅读』立即下载!

2014年3月影音播放软件行业数据TOP10

$
0
0

2014年3月,影音播放软件日均覆盖人数达1.3亿人。其中,QVOD日均覆盖人数达3296万人,网民到达率达9.8%,位居第一;iTunes日均覆盖人数达3258万人,网民到达率达9.7%,位居第二;暴风影音日均覆盖人数达2507万人,网民到达率达7.5%,位居第三。

2014年3月,影音播放软件有效使用时间达18.7亿小时。其中,暴风影音有效使用时间达7.6亿小时,占总有效使用时间的41%;迅雷看看播放器有效使用时间达2.9亿小时,占总有效使用时间的15.6%;QVOD有效使用时间达2.6亿小时,占总有效使用时间的13.9%。 

10款超炫HTML5游戏 附游戏源码

$
0
0

五一小长假开始了,小编为各位宅在家里的朋友分享10款超炫 HTML5游戏,让我们在不仅获得快乐的同时又可以学到新鲜的HTML5知识,一起来看看吧。

1、HTML5版切水果游戏 HTML5游戏极品

这是一款由百度JS小组提供的 HTML5版切水果游戏,记得切水果游戏当年非常火,今天我找到了一款基于HTML5实现的网页版切水果游戏。虽然和原版的切水果游戏相比功能不怎么完善,但是该HTML5切水果游戏也算有声有色,画面也十分华丽。

html5-fruit-ninja

在线演示       源码下载

2、HTML5中国象棋游戏 自定义象棋难度

棋类游戏在桌面游戏中已经非常成熟,中国象棋的版本也非常多。今天这款基于 HTML5技术的中国象棋游戏非常有特色,我们不仅可以选择中国象棋的游戏难度,而且可以切换棋盘的样式。程序写累了,喝上一杯咖啡,和电脑对弈几把吧,相信这HTML5中国象棋游戏的实现算法你比较清楚,可以打开源码来研究一下这款HTML5中国象棋游戏。

html5-zgxq

在线演示        源码下载

3、奇葩版Flappy Bird,HTML5 Flappy Text游戏

前段时间Flappy Bird游戏那是相当的火,有无数年轻人为之疯狂,我们也在 html5tricks网站上分享过一款 简易的HTML5版Flappy Bird。今天我们要分享一款奇葩版的Flappy Bird—— HTML5 Flappy Text游戏,用若干个字母来代替bird,每触碰一个障碍,字母就会少一个。一起来玩玩吧。

html5-flappy-text

在线演示        源码下载

4、HTML5五子棋游戏 画面超酷 可设置难度

前几天我向大家分享过一款 HTML5中国象棋游戏,效果令人惊叹,小编的实力很难胜过电脑。今天我要向大家分享一款 HTML5五子棋游戏,不仅游戏画面非常华丽,而且可以自己设置难度,并且可以选择人机对战还是人人对战,这款HTML5五子棋游戏绝对称得上HTML5游戏中的极品。

html5-5-chess

在线演示        源码下载

5、HTML5跳伞游戏 看谁先安全降落地面

今天我再来分享一款有趣的 HTML5游戏,HTML5跳伞游戏,是一款非常不错的HTML5休闲小游戏,主要应用了HTML5的重力感应效果。游戏一共四个玩家,主要是比谁先安全降落地面,绿色信号灯亮时,按下“X”键开始降落,然后再按“X”键打开降落伞进行安全降落,你需要控制好时机来按下“X”键和对手们比谁先安全降落。大家也可以在下面下载源代码学习分享。

html5-jumper-game

在线演示        源码下载

6、HTML5版Flappy Bird游戏 仅65行Javascript代码

Flappy Bird相信大家都很熟悉了,2014年最热门的手机游戏之一。Flappy Bird这款游戏是一位来自越南河内的独立游戏开发者阮哈东开发,形式简易但难度极高的休闲游戏,很容易让人上瘾。今天我们用 HTML5来重写这款Flappy Bird游戏,值得注意的是,利用Phaser框架,只需65行Javascript代码即可实现HTML5版的Flappy Bird游戏。 按空格键控制小鸟,试试看吧。

flappy-bird

在线演示        源码下载

7、HTML5吃豆人游戏PCMAN

今天又要介绍一款不错的 HTML5游戏,HTML5吃豆人游戏,画面上有一个吃豆人和一群怪物,你需要控制吃豆人移动吃掉路上的小豆子,一旦吃豆人遇到怪物被吃掉的时候,你就GAME OVER了。这款HTML5游戏还有一点没完善,就是吃豆人碰到怪物的时候不能被怪物吃掉,有兴趣的同学可以继续把它完善。HTML5游戏开发不仅需要技术,也需要创意。

html5-pcman

在线演示        源码下载

8、HTML5太空战机游戏 有声有色

这又是一款制作精良的 HTML5游戏,该HTML5游戏的主角是一架英勇威武的太空战机,进入游戏后按”Z”键发射子弹,消灭敌机。该HTML5战机游戏的特点是:1、游戏画面非常华丽逼真,并且加入声音元素,让游戏更加迷人;2、游戏元素很多,敌机类型和发射子弹类型也很多,让玩家不会枯燥。

html5-airplan-game

在线演示        源码下载

9、HTML5重力感应游戏 甩甩领导的头像

快过年了,工资没涨多少吧,年终奖没发吧,恨领导吧。现在利用这款 HTML5重力感应游戏来尽情甩领导的头像吧。制作一些你憎恨的领导们的头像图片,利用该HTML5重力感应游戏插件来拖动鼠标甩动这些头像,叫你不加工资…叫你不加工资…

html5-zlgy

在线演示        源码下载

10、HTML5超级玛丽游戏重体验 HTML5游戏经典

还记得小时候一起玩过的超级玛丽冒险游戏吗?是的,那是我们小时候很火的一款游戏,今天老外利用 HTML5技术让超级玛丽可以在网页上跑了,HTML5版的超级玛丽虽然没有原版的功能强大,但是如果你有兴趣,完全可以把它写完善了。HTML5真的很强大,HTML5游戏方面更是犀利。

html5-mario

在线演示        源码下载

以上就是10款超炫HTML5游戏及源码,祝大家五一快乐。

TinyMCE 4.0.24 发布,可视化 HTML 编辑器

$
0
0

TinyMCE 4.0.24 发布,此版本修复了一些小的 bug 和问题;添加了新的 event_root 设置,允许用户指定一个 CSS 选择器,用来定义所有应该绑定在内联模式 events 的 root 元素,这更容易转移到 DOM 的内联编辑器,而且不需要关联到编辑器事件。此版本还能指定一个 link_list 和 image_list 选项的自定义函数,允许用户制作一个自定义的 ajax 请求来填充这些列表。更多内容请看 发行说明

TinyMCE是一个轻量级的基于浏览器的所见即所得编辑器,支持目前流行的各种浏览器,由JavaScript写成。功能配置灵活简单(两行代码就可以 将编辑器嵌入网页中),支持AJAX。另一特点是加载速度非常快,如果你的服务器采用的脚本语言是 PHP,那还可以进一步优化。最重要的是,TinyMCE是一个根据LGPL license发布的自由软件,你可以把它用于商业应用。本站采用的就是TinyMCE编辑器,下图是此编辑器的界面

在线演示地址: http://tinymce.moxiecode.com/examples/full.php



PaaS平台– Google App Engine的开源实现AppScale环境搭建

$
0
0

搭建环境介绍:

  • 硬件平台:HP Z800 工作站  内存:24GB      硬盘:1TB
  • 虚拟化环境:XenServer 6.2.0
  • VM1:Ubuntu 12.04 amd64 server | IP:192.168.137.50
  • VM2:Ubuntu 12.04 amd64 server | IP:192.168.137.51
  • VM3:Ubuntu 12.04 amd64 server | IP:192.168.137.52

1、从Git安装Appscale

在Xen上安装好Ubuntu 12.04 server版本后,使用root用户登录,然后运行:

wget -O – http://bootstrap.appscale.com | sh

然后会从git clone到本地,进行自动化安装。该命令会执行下面的操作:

安装git

apt-get install -y git-core

构建appscale

cd /root
git clone git://github.com/AppScale/appscale.git
cd appscale/debian
bash appscale_build.sh

构建appscale-tools

cd /root
git clone git://github.com/AppScale/appscale-tools.git
cd appscale-tools/debian
bash appscale_build.sh

不出意外,基本可以完成自动化安装。如果报错,请Google。

2、VM准备

首先将上面安装的VM进行clone,这里使用,复制出VM1和VM2。

然后对每个VM进行设置静态IP:修改每个VM的/etc/network/interfaces文件

VM1:

1auto eth0
2iface eth0 inet static
3address 192.168.137.50
4netmask 255.255.255.0
5gateway 192.168.137.1
6dns-nameservers 114.114.114.114

VM2:

1auto eth0
2iface eth0 inet static
3address 192.168.137.51
4netmask 255.255.255.0
5gateway 192.168.137.1
6dns-nameservers 114.114.114.114

VM3:

1auto eth0
2iface eth0 inet static
3address 192.168.137.52
4netmask 255.255.255.0
5gateway 192.168.137.1
6dns-nameservers 114.114.114.114

对应也修改每个VM的主机名。(配置文件/etc/hostname)

3、准备启动

三个VM重新启动后,在master上运行:

1appscale init cluster

初始化集群。

修改自动生成的配置文件:AppScalefile

1ips_layout :
2  master : 192.168.137.50
3  appengine : 192.168.137.50
4  database : 192.168.137.51
5  zookeeper : 192.168.137.52

 4、启动集群

执行命令:

1appscale up

看到以下输出信息:

01Starting AppScale 1.14.0 over a virtualized cluster.
02Log in to your head node: ssh -i /root/.appscale/appscale6099037d27e2439c8396c88148e5037b.key root@192.168.137.50
03Head node successfully initialized at 192.168.137.50. It is now starting up cassandra.
04Copying over deployment credentials
05Starting AppController at 192.168.137.50
06Please wait for the AppController to finish pre-processing tasks.
07 
08Please wait for AppScale to prepare your machines for use.
09Copying over needed files and starting the AppController on the other VMs
10UserAppServer is at 192.168.137.51
11Enter your desired admin e-mail address: admin@geekcome.com
12Enter new password:
13Confirm password:
14Creating new user account admin@geekcome.com
15Creating new user account admin@192.168.137.50
16Your XMPP username is admin@192.168.137.50
17Granting admin privileges to admin@geekcome.com
18AppScale successfully started!
19View status information about your AppScale deployment at  http://192.168.137.50:1080/status

这样就成功启动。

使用命令查看appscale status查看集群的状态:


可以登录web管理端:https://192.168.137.50:1443/


作者:GeekCome
出处:极客来
提示:本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
如果对文章有任何问题,都可以在评论中留言,我会尽可能的答复您,谢谢你的阅读



(完)

作者:yming0221 发表于2014-5-1 15:45:55 原文链接
阅读:118 评论:0 查看评论

G1,CMS及PARALLEL GC的比较

$
0
0

这篇文章正好接上前一年我们做的一次现实环境下不同GC算法性能比较的试验。这次我们仍然进行同样的试验,不过增加了对G1回收器的测试,并且在多个平台进行测试。今年我们测试的垃圾回收器有如下几个:

  • -XX:+UseParallelOldGC
  • -XX:+UseConcMarkSweepGC
  • -XX:+UseG1GC

运行环境

我们使用现成的 JIRA任务来运行这个测试。选择它的原因非常简单——除去Minecraft(一款著名网游),愤怒的小鸟,以及Eclipse不说, JIRA应该是最著名的Java应用程序了。并且和别的候选者相比,它更能代表我们日常的业务处理流程——毕竟来说Java用得最多的地方还是在服务端的Java企业级应用。

影响我们决定的还有一个因素—— Atlassian的工程师们发布了一个打包好的JIRA压测脚本 。我们可以直接用它来进行我们的基准测试。

我们仔细的将最新版的JIRA6.1解压,然后把它安装到Mac OS X Mavericks上。最后直接使用默认的内存参数设置来运行这个测试程序。Atlassian团队的家伙已经帮我们把参数也设置好了:

-Xms256m -Xmx768m -XX:MaxPermSize=256m

这个程序使用了JIRA的常见的几种不同功能——创建任务,分配任务,解析任务,查找及发现任务,等等。总的运行时间是30分钟。

我们使用了三种不同的GC算法来运行这个测试——Parallel,CMS, 和G1。每次测试都重新启动一个新的JVM实例,并事先把存储恢复到同样的状态。一切准备就绪后我们才开始启动压测。

结果

每次测试我们都通过-XX:+PrintGCTimeStamps -Xloggc:/tmp/gc.log -XX:+PrintGCDetails来收集GC日志,最后使用GCViewer来分析里面的数据。

汇总后的结果如下。注意测试结果的单位是毫秒。

ParallelCMSG1
Total GC pauses20 93018 87062 000
Max GC pause7216450

说明

首先来看Parallel GC (-XX:+UseParallelOldGC)。在这30分钟的测试过程中,并行收集器的GC大概暂停了有21秒。最长的一次花了721毫秒。我们来以这个做为基准:从总的运行时间来看,GC周期减少了1.1%的吞吐量。最长的延迟时间大概是721毫秒。

下一个:CMS(-XX:+UseConcMarkSweepGC)。在30分钟的测试中,由于GC而损失的时间是19秒。吞吐量和上一次的并行模式下的差不多。不过时延方面有了明显的改善——最坏的情况下的时延减少了10倍!现在最大的GC暂停时间只有64毫秒。

最后一次测试用的是最新最潮的GC算法——GC(-XX:+UseG1GC)。运行的是同样的测试程序,不过结果的吞吐量则严重下降了。这次测试应用在GC上花费的时间超过了一分钟。和CMS只有1%的开销相比,这次的吞吐量下降了有3.5%。不过如果你不在乎吞吐量而更在乎时延的话——这方面它和前面表现最好的CMS相比还有20%的提升——G1回收器最长的暂停时间只有50ms。

结论

想通过这么一次试验来得出一个结论是非常危险的。如果你的时间充足又有相应的能力的话——你应该在自己的环境中具体情况具体分析,而不是使用一刀切的方法。

不过如果说非要得出一个结论,我认为说CMS仍然是最佳的默认选择。G1的吞吐量实在是太差,和它所减少的那点时延相比并不划算。

原创文章转载请注明出处: G1,CMS及PARALLEL GC的比较

英文原文链接

屌丝就爱尝鲜头——java8初体验 - laozhu1124

$
0
0

  Java8已经推出,让我们看看他的魅力。让我们看看他改变较大的部分。

  一、java8概述

  Java8是由Oracle(甲骨文)公司与2014年3月27日正式推出的。Java8同时推出有3套语言系统,分别是Java SE8、Java SE Emebbled 8、Java ME8。

  Java SE8较以往的系统增强的功能有:

  ①增强了对集合式操作语言——lambda表达式的支持,“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。注意Lambda表达式在C#,c++等语言中得到广泛的应用,因此Java SE8将其纳入了其中。

  ②增强一些新的时间操作的api,让你对Java中的时间操作不再那么的烦恼。总而言之,就是Instant,LocalDate,LocalTime和LocalDateTime这几个类,让你操作时间的不再需要指定所谓的时区,系统自动判断,这样我们程序员的工作轻松了很多。

  ③Java SE8 引入了全新的Nashorn js 解析引擎,这个新的解释器将会代替Java现有的Rhino解释器。据说它执行JavaScript的速度非常之快,就像世界上最快的跑车 V8s。

  ④Java SE8 省去了不少的配置工作,这样ssh架构不再繁琐。

  ⑤增强对一些了编译前的代码的异常的动态的判断,例如妈妈再也不用担心我的空指针问题的异常了。

  ⑥去掉Jvm process 影响,性能大大的增加。

  Java Emblemed SE8 与Java SE8一样的api,不同的是能够使用更小的架构来建立相应的应用。

  Java SE8 主要使其Java 更加专注与嵌入式设备的开发,例如,机顶盒的开发。 

  二、下载JDK8

  在Google中,输入Java 8 download Oracle,如图:

  

  打开相应的连接,打开Oracle的下载页面,我这里是windows x64位,所以进行x64位的下载。如图:

 

  这样,就下好了。

  三安装JDK8

   将jdk8下载以后,进行下一步下一步以后就安装好了。如图所示:

  

 

  四在eclipse中使用JDK
  注意了eclipse一定4.4及其以上的版本,eclipse4.4以下版本不支持Java se8。所以了需要下载eclipse4.4以上的版本了,这里了就不做过多的赘述。

  五lambda概述

  首先,我们这里简单明白了lambda表达式的定义。Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

  lambda表达式解决了Java语言的一些顽疾有:

  Java不能像函数式语言 ,实现了函数的嵌套。

  匿名内部类虽然能够实现当前线程的调用,但是不能够跨线程调用。

  匿名内部类还带来了一个坏处,就是this与当前对象无非区别。

  Java不能调用外部非静态非final对象。

  这种函数式接口,我们总结为:

  函数式接口(functional interface 也叫功能性接口,其实是同一个东西)。简单来说,函数式接口是只包含一个方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断,但 最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。

  Lambda语法

  包含三个部分

  一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数

  一个箭头符号:->

  方法体,可以是表达式和代码块,方法体函数式接口里面方法的实现,如果是代码块,则必须用{}来包裹起来,且需要一个return 返回值,但有个例外,若函数式接口里面方法返回值是void,则无需{}

  总体看起来像这样

  1(parameters) -> expression 或者 (parameters) -> { statements; }

  这就是我对lambda的概述。

  以上篇幅,是我对java8的一些初体验,Java8的体验是确实是在性能有所提高,大概提高15%左右,对语法检测也有所增强,对lambda表达式引入无非是Java8最大的亮点,这样子,我们在写函数操作时候,更加方便,总而言子,Java8一切为了开发人员


本文链接: 屌丝就爱尝鲜头——java8初体验,转载请注明。

9个建议让你的网站更适用于特殊人群

$
0
0

互联网设计不能“一锅端”。在我们的生活中,每天都有数以万计糟糕的设计阻碍老人、残疾人等特殊人群使用互联网。

对于那些视力、听力、以及学习能力上有障碍的人们来说,在每一个URL后面都隐藏着巨大的使用障碍。但是,建立一个适用于这种特殊人群的网站并没有你想象得那么难。

英国籍设计师Laurence Berry曾说, 要想设计出一个适用于某类用户的产品,首先要明白他们所要面对的障碍。这句话听起来似乎显而易见,但是这确实设计出适用于用户产品的第一步。

了解释第一步,那么实行就是第二步。虽然程序看似繁杂,但如果你不去这样做得话,你的用户就会在适用产品时遇到更多的障碍。

盲人设计师Sandi Wassmer也表明了在设计上“多走一步”的必要:“如果你的产品仅仅作为商业用途,那么不考虑特殊人士,将会让你失去一大块市场。”

他还告诫人们不要忽略另一个人群——老人。老年人随着身体的老化会丧失一些机能,不似年轻人一样敏感。所以,这种考虑到老年人的需求也是十分必要的。

希望这个文章能帮助你设计出一个适合这种特殊人士的网站。下面是一些小建议,希望可以帮助你在设计上进一步提高:

一、使用alt tags

当你把鼠标停留在某一个网站或图片上,alt tags可以帮助你大声读出文本。对于那些视力上有障碍的人们来说,读出来事唯一可以让他们知道图像、文字在哪里的方式。对于图像,如果是一个人,我们可以编辑出他的名字。如果是一幅画,我们可以加上几句简单的介绍。总之,alt tags是帮助特殊人士正确定位的最佳工具。

二、加字母及文稿

如果你的网站有大量视频,尤其是视频是你自己制作的时候,请务必加上字幕。很多热门网站例如youtube就设定了加载字幕的功能。这些字幕对于听力有障碍的人来说是巨大的辅助。

三、在所写中间放点或句号

在编辑HTML时,很多缩写会给用户带来很多麻烦。例如CIA,如果不加上英文句点写成C.I.A.,会被直接当成词语cia。

四、解释你的链接

很多链接在设置时被直接写成“点我”,但是用户却并不了解这个点击背后的内容。为了使用户能够更清晰地定位他们想要找的内容,更好的方式是在内容下面直接放上链接,或给连接一个简短的介绍。例如,我们可以用点击查看“网站科技频道”,而非“点击这里”。另外,确保链接颜色与其它文字区分开。

五、慎重选择颜色

黑字白板一般是最好的选择,易于用户阅读。在选择颜色时,总要考虑用户到底想要什么颜色,什么颜色让他们看起来更舒服。

六、确保每一个链接都可以被点到

很多使用智能设备用户会遇到一些点击的困难。例如,一个很小的链接很难在手机上被点到。这时,设计师就要注意,确保屏幕可以缩放,让用户可以轻松地点击到每一个链接。

七、让你的内容简洁明了

对于老人或一些学习有障碍的人来说,简单的内容会让他们在使用时更轻松。例如,我们可以将长的内容分成几段、用简洁的语言等。

八、写一份使用指导

对于很多不熟悉互联网、或是有学习能力障碍的人来说,一份指导教程可以帮助他们更好的使用网站。

九、了解你的用户

把你自己想象成用户,总能帮助你更好的设计。另外,多观察周围的人们或者你的用户群是如何适用产品的,了解你的用户总能帮助你更好的设计出适合他们的产品。

(via mashable 译/快鲤鱼)


(关注更多人人都是产品经理观点,参与微信互动(微信搜索“人人都是产品经理”或“woshipm”)

中国造不出像样的汽车发动机,是真的吗?

$
0
0
这是真的。

车用发动机,技术难度高(涉及流体力学 燃烧学 振动学等学科),投入大,获利周期长。既然现在有外国的用,没人愿意花钱自己做研发。更何况就算研发出来,国内的材料水平以及制造水平也跟不上。不过发动机这东西毕竟发展了很多年了,很多结构和部件定型了之后很难做出改变。目前国内厂家(潍柴、玉柴等)都是在做原型基础上做些不痛不痒的修改。

国内整个行业的人都是急功近利,没人愿意搞研究。就说缸内气体燃烧这一项 国内搞这个的人寥寥无几 有也只是纯理论层面的研究,想做个实验,整个中国都没有这个条件。

至于说汽车技术里面哪些是国产的,我可以明确的告诉你几个哪几个不是国产的:

1 汽油发动机(生产有 但核心技术不在我 低端有 差距大)

2 自动变速箱(国内空白 不过吉利收购了澳大利亚的DSI )

3 汽车电控方面(ABS,ASR,ESP等 空白 基本被博世 德尔福垄断)

4 汽车造型设计(号称自主研发其实多为抄袭) 2011-07-02

--------------------------------------三年后(2014-04-15)更新----------------------------------------
没想到三年多没管 这个问题还有这么多人关注。当年回答这个问题的时候楼主还是个学生,在世界顶尖的供应商公司做intern,现在却已踏入工作岗位了,成了一名汽车工程师。楼主毕业时拒了BOSCH和ZF提供的岗位,来到了 某汽集团 做混动系统的控制。
说到发动机,现在某汽集团即将把旧发动机全部切换成“在全球范围内共享知识产权”的新发动机,这一系列新发动机研发全部是GM做,GM和某汽的车子都会用,硬件和基础软件全部一样,只是标定数据会不同。
为什么不用自己的?因为旧的发动机油耗动力都不行,新开发的性能比不过市场主流,综合考虑,用GM的发动机是性价比最优的选择。更何况经济危机的时候,某汽花5亿rmb购入GM 1%的股权,在破产边缘救了它一把,这个共享知识产权的发动机实际就是当时的回报。
当然某汽也在消化这些技术,这需要时间。
发动机这一块话不多说,楼下兄弟把硬件这一块讲的也很清楚。我们来聊聊混动系统:
1. 混动系统控制器硬件和底层实际还是Bosch的,但是应用层自己开发的。应用层软件是整个控制系统的核心,这一块我们也累积了很多经验和能力,即使和BOSCH、ZF、DENSO等巨头合作也丝毫不虚。
2. 电机也是类似,但是电机有个好处是国内的电机制造水平似乎并不弱(得益於航空航天的巨大投入?)国产电机性能良好,控制也是自己做应用层控制,这一块我们能力亦有自信。
3. 电池是用美国和韩国的,目前我们能力确实不足。

现实确实如问题描述中所说,但我们仍在追赶。
BYD做的不错,
某汽也不错,
希望过几年再来看时能够改写这个答案。

— 完 —
本文作者: 知乎用户(登录查看详情)

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 62 个回答,查看全部。
延伸阅读:
行车过程中非加速状态下为什么要保持发动机怠速转动?
手动挡汽车在换挡的瞬间离合被踩到底,在那段时间里发动机是空转的,动力没有传到轮胎,造成了浪费,为何依旧比同排量的自动挡汽车省油?

如何写出高性能SQL语句

$
0
0

优化SQL查询:如何写出高性能SQL语句。

1、首先要搞明白什么叫执行计划?

执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生欀如一条SQL语句如果用来从一个10万条记录的表中查1条记录,那查询优化器会选择“索引查找”方式,如果该表进行了归档,当前只剩下5000条记录了,那查询优化器就会改变方案,采用“全表扫描”方式。

可见,执行计划并不是固定的,它是“个性化的”。产生一个正确的“执行计划”有两点很重要:

(1) SQL语句是否清晰地告诉查询优化器它想干什么?

(2) 查询优化器得到的数据库统计信息是否是最新的、正确的?

2、统一SQL语句的写法

对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的。

select * from dual
select * From dual

其实就是大小写不同,查询分析器就认为是两句不同的SQL语句,必须进行两次解析。生成2个执行计划。所以作为程序员,应该保证相同的查询语句在任何地方都一致,多一个空格都不行!

3、不要把SQL语句写得太复杂

我经常看到,从数据库中捕捉到的一条SQL语句打印出来有2张A4纸这么长。一般来说这么复杂的语句通常都是有问题的。我拿着这2页长的SQL语句去请教原作者,结果他说时间太长,他一时也看不懂了。可想而知,连原作者都有可能看糊涂的SQL语句,数据库也一样会看糊涂。

一般,将一个Select语句的结果作为子集,然后从该子集中再进行查询,这种一层嵌套语句还是比较常见的,但是根据经验,超过3层嵌套,查询优化器就很容易给出错误的执行计划。因为它被绕晕了。像这种类似人工智能的东西,终究比人的分辨力要差些,如果人都看晕了,我可以保证数据库也会晕的。

另外,执行计划是可以被重用的,越简单的SQL语句被重用的可能性越高。而复杂的SQL语句只要有一个字符发生变化就必须重新解析,然后再把这一大堆垃圾塞在内存里。可想而知,数据库的效率会何等低下。

4、使用“临时表”暂存中间结果

简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。

5、OLTP系统SQL语句必须采用绑定变量

select * from orderheader where changetime > ’2010-10-20 00:00:01′
select * from orderheader where changetime > ’2010-09-22 00:00:01′

以上两句语句,查询优化器认为是不同的SQL语句,需要解析两次。如果采用绑定变量:

select * from orderheader where changetime > @chgtime

@chgtime变量可以传入任何值,这样大量的类似查询可以重用该执行计划了,这可以大大降低数据库解析SQL语句的负担。一次解析,多次重用,是提高数据库效率的原则。

6、绑定变量窥测

事物都存在两面性,绑定变量对大多数OLTP处理是适用的,但是也有例外。比如在where条件中的字段是“倾斜字段”的时候。

“倾斜字段”指该列中的绝大多数的值都是相同的,一张人口调查表,其中“民族”这列,90%以上都是汉族。那么如果一个SQL语句要查询30岁的汉族人口有多少,那“民族”这列必然要被放在where条件中。这个时候如果采用绑定变量@nation会存在很大问题。

试想如果@nation传入的第一个值是“汉族”,那整个执行计划必然会选择表扫描。然后,第二个值传入的是“布依族”,按理说“布依族”占的比例可能只有万分之一,应该采用索引查找。但是,由于重用了第一次解析的“汉族”的那个执行计划,那么第二次也将采用表扫描方式。这个问题就是著名的“绑定变量窥测”,建议对于“倾斜字段”不要采用绑定变量。

7、 只在必要的情况下才使用begin tran

SQL Server中一句SQL语句默认就是一个事务,在该语句执行完成后也是默认commit的。其实,这就是begin tran的一个最小化的形式,好比在每句语句开头隐含了一个begin tran,结束时隐含了一个commit。

有些情况下,我们需要显式声明begin tran,比如做“插、删、改”操作需要同时修改几个表,要求要么几个表都修改成功,要么都不成功。begin tran可以起到这样的作用,它可以把若干SQL语句套在一起执行,最后再一起commit。好处是保证了数据的一致性,但任何事情都不是完美无缺的。Begin tran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。

可见,如果Begin tran套住的SQL语句太多,那数据库的性能就糟糕了。在该大事务提交之前,必然会阻塞别的语句,造成block很多。

Begin tran使用的原则是,在保证数据一致性的前提下,begin tran套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begin tran。

8、一些SQL查询语句应加上nolock

在SQL语句中加nolock是提高SQL Server并发性能的重要手段,在oracle中并不需要这样做,因为oracle的结构更为合理,有undo表空间保存“数据前影”,该数据如果在修改中还未commit,那么你读到的是它修改之前的副本,该副本放在undo表空间中。这样,oracle的读、写可以做到互不影响,这也是oracle广受称赞的地方。

SQL Server的读、写是会相互阻塞的,为了提高并发性能,对于一些查询,可以加上nolock,这样读的时候可以允许写,但缺点是可能读到未提交的脏数据。使用nolock有3条原则。

(1) 查询的结果用于“插、删、改”的不能加nolock!

(2) 查询的表属于频繁发生页分裂的,慎用nolock!

(3) 使用临时表一样可以保存“数据前影”,起到类似oracle的undo表空间的功能,

能采用临时表提高并发性能的,不要用nolock 。

9、聚集索引没有建在表的顺序字段上,该表容易发生页分裂

比如订单表,有订单编号orderid,也有客户编号contactid,那么聚集索引应该加在哪个字段上呢?对于该表,订单编号是顺序添加的,如果在orderid上加聚集索引,新增的行都是添加在末尾,这样不容易经常产生页分裂。然而,由于大多数查询都是根据客户编号来查的,因此,将聚集索引加在contactid上才有意义。而contactid对于订单表而言,并非顺序字段。

比如“张三”的“contactid”是001,那么“张三”的订单信息必须都放在这张表的第一个数据页上,如果今天“张三”新下了一个订单,那该订单信息不能放在表的最后一页,而是第一页!如果第一页放满了呢?很抱歉,该表所有数据都要往后移动为这条记录腾地方。

SQL Server的索引和Oracle的索引是不同的,SQL Server的聚集索引实际上是对表按照聚集索引字段的顺序进行了排序,相当于oracle的索引组织表。SQL Server的聚集索引就是表本身的一种组织形式,所以它的效率是非常高的。也正因为此,插入一条记录,它的位置不是随便放的,而是要按照顺序放在该放的数据页,如果那个数据页没有空间了,就引起了页分裂。所以很显然,聚集索引没有建在表的顺序字段上,该表容易发生页分裂。

曾经碰到过一个情况,一位哥们的某张表重建索引后,插入的效率大幅下降了。估计情况大概是这样的。该表的聚集索引可能没有建在表的顺序字段上,该表经常被归档,所以该表的数据是以一种稀疏状态存在的。比如张三下过20张订单,而最近3个月的订单只有5张,归档策略是保留3个月数据,那么张三过去的15张订单已经被归档,留下15个空位,可以在insert发生时重新被利用。在这种情况下由于有空位可以利用,就不会发生页分裂。但是查询性能会比较低,因为查询时必须扫描那些没有数据的空位。

重建聚集索引后情况改变了,因为重建聚集索引就是把表中的数据重新排列一遍,原来的空位没有了,而页的填充率又很高,插入数据经常要发生页分裂,所以性能大幅下降。

对于聚集索引没有建在顺序字段上的表,是否要给与比较低的页填充率?是否要避免重建聚集索引?是一个值得考虑的问题!

10、加nolock后查询经常发生页分裂的表,容易产生跳读或重复读

加nolock后可以在“插、删、改”的同时进行查询,但是由于同时发生“插、删、改”,在某些情况下,一旦该数据页满了,那么页分裂不可避免,而此时nolock的查询正在发生,比如在第100页已经读过的记录,可能会因为页分裂而分到第101页,这有可能使得nolock查询在读101页时重复读到该条数据,产生“重复读”。同理,如果在100页上的数据还没被读到就分到99页去了,那nolock查询有可能会漏过该记录,产生“跳读”。

上面提到的哥们,在加了nolock后一些操作出现报错,估计有可能因为nolock查询产生了重复读,2条相同的记录去插入别的表,当然会发生主键冲突。

11、使用like进行模糊查询时应注意

有的时候会需要进行一些模糊查询比如

select * from contact where username like ‘%yue%’

关键词%yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%,

12、数据类型的隐式转换对查询效率的影响

SQL Server2000的数据库一的程序在提交sql语句的时候,没有使用强类型提交这个字段的值,由SQL Server 2000自动转换数据类型,会导致传入的参数与主键字段类型不一致,这个时候SQL Server 2000可能就会使用全表扫描。Sql2005上没有发现这种问题,但是还是应该注意一下。

13、SQL Server表连接的三种方式

(1) Merge Join

(2) Nested Loop Join

(3) Hash Join

SQL Server 2000只有一种join方式——Nested Loop Join,如果A结果集较小,那就默认作为外表,A中每条记录都要去B中扫描一遍,实际扫过的行数相当于A结果集行数x B结果集行数。所以如果两个结果集都很大,那Join的结果很糟糕。

SQL Server 2005新增了Merge Join,如果A表和B表的连接字段正好是聚集索引所在字段,那么表的顺序已经排好,只要两边拼上去就行了,这种join的开销相当于A表的结果集行数加上B表的结果集行数,一个是加,一个是乘,可见merge join的效果要比Nested Loop Join好多了。

如果连接的字段上没有索引,那SQL2000的效率是相当低的,而SQL2005提供了Hash join,相当于临时给A,B表的结果集加上索引,因此SQL2005的效率比SQL2000有很大提高,我认为,这是一个重要的原因。

总结一下,在表连接时要注意以下几点:

(1) 连接字段尽量选择聚集索引所在的字段

(2) 仔细考虑where条件,尽量减小A、B表的结果集

(3) 如果很多join的连接字段都缺少索引,而你还在用SQL Server 2000,赶紧升级吧。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



面向对象编程的五大原则

$
0
0
  • 单一职责原则
  • 开放封闭原则
  • 里氏替换原则
  • 依赖倒置原则
  • 接口隔离原则

       高层的实现不应该依赖底层,(父类可以替换掉任何子类),具体说就是我们要针对接口抽象来编程,不要针对实现来编程,这样程序才能解耦。

 

一、“开-闭”原则(Open-Closed Principle,OCP)

1.1 “开-闭”原则的定义及优点

1)定义:一个软件实体应当对扩展开放,对修改关闭( Software entities should be open for extension,but closed for modification.)。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。

2)满足“开-闭”原则的系统的优点

a)通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。

b)已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。

c)这样的系统同时满足了可复用性与可维护性。

 

1.2 如何实现“开-闭”原则

       在面向对象设计中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。换言之,定义一个一劳永逸的抽象设计层,允许尽可能多的行为在实现层被实现。

       解决问题关键在于抽象化,抽象化是面向对象设计的第一个核心本质。

       对一个事物抽象化,实质上是在概括归纳总结它的本质。抽象让我们抓住最最重要的东西,从更高一层去思考。这降低了思考的复杂度,我们不用同时考虑那么多的东西。换言之,我们封装了事物的本质,看不到任何细节。

       在面向对象编程中,通过抽象类及接口,规定了具体类的特征作为抽象层,相对稳定,不需更改,从而满足“对修改关闭”;而从抽象类导出的具体类可以改变系统的行为,从而满足“对扩展开放”。

       对实体进行扩展时,不必改动软件的源代码或者二进制代码。关键在于抽象。

 

1.3 对可变性的封装原则

      “开-闭”原则也就是“对可变性的封装原则”(Principle of Encapsulation of Variation ,EVP)。即找到一个系统的可变因素,将之封装起来。换言之,在你的设计中什么可能会发生变化,应使之成为抽象层而封装,而不是什么会导致设计改变才封装。

      “对可变性的封装原则”意味着:

a) 一种可变性不应当散落在代码的许多角落,而应当被封装到一个对象里面。同一可变性的不同表象意味着同一个继承等级结构中的具体子类。因此,此处可以期待继承关系的出现。继承是封装变化的方法,而不仅仅是从一般的对象生成特殊的对象。

b) 一种可变性不应当与另一种可变性混合在一起。作者认为类图的继承结构如果超过两层,很可能意味着两种不同的可变性混合在了一起。

使用“可变性封装原则”来进行设计可以使系统遵守“开-闭”原则。

即使无法百分之百的做到“开-闭”原则,但朝这个方向努力,可以显著改善一个系统的结构。

 

二、里氏代换原则(Liskov Substitution Principle, LSP)

2.1 概念

1)定义:如果对每一个类型为T1的对象O1,都有类型为T2 的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换为O2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。

       即,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类。而且它觉察不出基类对象和子类对象的区别。也就是说,在软件里面,把基类都替换成它的子类,程序的行为没有变化。

       反过来的代换不成立,如果一个软件实体使用的是一个子类的话,那么它不一定适用于基类。

任何基类可以出现的地方,子类一定可以出现。

基于契约的设计、抽象出公共部分作为抽象基类的设计。

 

2.2 里氏代换原则与“开-闭”原则的关系

       实现“开-闭”原则的关键步骤是抽象化。基类与子类之间的继承关系就是抽象化的体现。因此里氏代换原则是对实现抽象化的具体步骤的规范。

违反里氏代换原则意味着违反了“开-闭”原则,反之未必。

里氏替换原则:其子类对象可以代替父类对象,但其父类对象不能代替子类对象.
如:有一个父类:public   abstract   class   A{}
     有两个子类都继承父类A: 
              public   class   B:A{} 
              public   class   C:A[]
     那么运用里氏替换原则就可以: 
              A   a   =   new   B();或:A   a   =   new   C();
     但不可以:   B   b   =   new   A();

 

三、 依赖倒转原则(dependence inversion principle, DIP)

3.1 概念

       依赖倒转原则就是要依赖于抽象,不要依赖于实现。(Abstractions should not depend upon details. Details should depend upon abstractions.)要针对接口编程,不要针对实现编程。(Program to an interface, not an implementation.)

       也就是说应当使用接口和抽象类进行变量类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。而不要用具体类进行变量的类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。要保证做到这一点,一个具体类应当只实现接口和抽象类中声明过的方法,而不要给出多余的方法。

       传统的过程性系统的设计办法倾向于使高层次的模块依赖于低层次的模块,抽象层次依赖于具体层次。倒转原则就是把这个错误的依赖关系倒转过来。

       面向对象设计的重要原则是创建抽象化,并且从抽象化导出具体化,具体化给出不同的实现。继承关系就是一种从抽象化到具体化的导出。

       抽象层包含的应该是应用系统的商务逻辑和宏观的、对整个系统来说重要的战略性决定,是必然性的体现。具体层次含有的是一些次要的与实现有关的算法和逻辑,以及战术性的决定,带有相当大的偶然性选择。具体层次的代码是经常变动的,不能避免出现错误。

       从复用的角度来说,高层次的模块是应当复用的,而且是复用的重点,因为它含有一个应用系统最重要的宏观商务逻辑,是较为稳定的。而在传统的过程性设计中,复用则侧重于具体层次模块的复用。

       依赖倒转原则则是对传统的过程性设计方法的“倒转”,是高层次模块复用及其可维护性的有效规范。

       特例:对象的创建过程是违背“开—闭”原则以及依赖倒转原则的,但通过工厂模式,能很好地解决对象创建过程中的依赖倒转问题。

 

3.2 关系

       “开-闭”原则与依赖倒转原则是目标和手段的关系。如果说开闭原则是目标,依赖倒转原则是到达"开闭"原则的手段。如果要达到最好的"开闭"原则,就要尽量的遵守依赖倒转原则,依赖倒转原则是对"抽象化"的最好规范。

里氏代换原则是依赖倒转原则的基础,依赖倒转原则是里氏代换原则的重要补充。

 

3.3 耦合(或者依赖)关系的种类:

  • 零耦合(Nil Coupling)关系:两个类没有耦合关系

  • 具体耦合(Concrete Coupling)关系:发生在两个具体的(可实例化的)类之间,经由一个类对另一个具体类的直接引用造成。

  • 抽象耦合(Abstract Coupling)关系:发生在一个具体类和一个抽象类(或接口)之间,使两个必须发生关系的类之间存有最大的灵活性。

3.3.1 如何把握耦合

        我们应该尽可能的避免实现继承,原因如下:

  • 失去灵活性,使用具体类会给底层的修改带来麻烦。

  • 耦合问题,耦合是指两个实体相互依赖于对方的一个量度。程序员每天都在(有意识地或者无意识地)做出影响耦合的决定:类耦合、API耦合、应用程序耦合等等。在一个用扩展的继承实现系统中,派生类是非常紧密的与基类耦合,而且这种紧密的连接可能是被不期望的。如B extends A ,当B不全用A中的所有methods时,这时候,B调用的方法可能会产生错误!

我们必须客观的评价耦合度,系统之间不可能总是松耦合的,那样肯定什么也做不了。

 

3.3.2 我们决定耦合的程度的依据何在呢?

       简单的说,就是根据需求的稳定性,来决定耦合的程度。对于稳定性高的需求,不容易发生变化的需求,我们完全可以把各类设计成紧耦合的(我们虽然讨论类之间的耦合度,但其实功能块、模块、包之间的耦合度也是一样的),因为这样可以提高效率,而且我们还可以使用一些更好的技术来提高效率或简化代码,例如c# 中的内部类技术。可是,如果需求极有可能变化,我们就需要充分的考虑类之间的耦合问题,我们可以想出各种各样的办法来降低耦合程度,但是归纳起来,不外乎增加抽象的层次来隔离不同的类,这个抽象层次可以是抽象的类、具体的类,也可以是接口,或是一组的类。我们可以用一句话来概括降低耦合度的思想:"针对接口编程,而不是针对实现编程。

       在我们进行编码的时候,都会留下我们的指纹,如public的多少,代码的格式等等。我们可以耦合度量评估重新构建代码的风险。因为重新构建实际上是维护编码的一种形式,维护中遇到的那些麻烦事在重新构建时同样会遇到。我们知道在重新构建之后,最常见的随机bug大部分都是不当耦合造成的。

如果不稳定因素越大,它的耦合度也就越大。

某类的不稳定因素 = 依赖的类个数/被依赖的类个数

依赖的类个数 = 在编译此类的时被编译的其它类的个数总和

 

3.3.3 怎样将大系统拆分成小系统

       解决这个问题的一个思路是将许多类集合成一个更高层次的单位,形成一个高内聚、低耦合的类的集合,这是我们设计过程中应该着重考虑的问题!

       耦合的目标是维护依赖的单向性,有时我们也会需要使用坏的耦合。在这种情况下,应当小心记录下原因,以帮助日后该代码的用户了解使用耦合真正的原因。

 

3.4 怎样做到依赖倒转?

       以抽象方式耦合是依赖倒转原则的关键。抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引用到基类的地方都可以改换成其子类,因此,里氏代换原则是依赖倒转原则的基础。

       在抽象层次上的耦合虽然有灵活性,但也带来了额外的复杂性,如果一个具体类发生变化的可能性非常小,那么抽象耦合能发挥的好处便十分有限,这时可以用具体耦合反而会更好。       层次化:所有结构良好的面向对象构架都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供一组内聚的服务。依赖于抽象:建议不依赖于具体类,即程序中所有的依赖关系都应该终止于抽象类或者接口。尽量做到:1、任何变量都不应该持有一个指向具体类的指针或者引用。2、任何类都不应该从具体类派生。3、任何方法都不应该覆写它的任何基类中的已经实现的方法。

 

3.5 依赖倒转原则的优缺点

       依赖倒转原则虽然很强大,但却最不容易实现。因为依赖倒转的缘故,对象的创建很可能要使用对象工厂,以避免对具体类的直接引用,此原则的使用可能还会导致产生大量的类,对不熟悉面向对象技术的工程师来说,维护这样的系统需要较好地理解面向对象设计。

       依赖倒转原则假定所有的具体类都是会变化的,这也不总是正确。有一些具体类可能是相当稳定,不会变化的,使用这个具体类实例的应用完全可以依赖于这个具体类型,而不必为此创建一个抽象类型。

 

四、合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP)

 4.1 概念

1)定义:在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。

       应首先使用合成/聚合,合成/聚合则使系统灵活,其次才考虑继承,达到复用的目的。而使用继承时,要严格遵循里氏代换原则。有效地使用继承会有助于对问题的理解,降低复杂度,而滥用继承会增加系统构建、维护时的难度及系统的复杂度。

       如果两个类是“Has-a”关系应使用合成、聚合,如果是“Is-a”关系可使用继承。"Is-A"是严格的分类学意义上定义,意思是一个类是另一个类的"一种"。而"Has-A"则不同,它表示某一个角色具有某一项责任。

 

4.2 什么是合成?什么是聚合?

       合成(Composition)和聚合(Aggregation)都是关联(Association)的特殊种类。

       聚合表示整体和部分的关系,表示“拥有”。如奔驰S360汽车,对奔驰S360引擎、奔驰S360轮胎的关系是聚合关系,离开了奔驰S360汽车,引擎、轮胎就失去了存在的意义。在设计中, 聚合不应该频繁出现,这样会增大设计的耦合度。

       合成则是一种更强的“拥有”,部分和整体的生命周期一样。合成的新的对象完全支配其组成部分,包括它们的创建和湮灭等。一个合成关系的成分对象是不能与另一个合成关系共享的。

       换句话说,合成是值的聚合(Aggregation by Value),而一般说的聚合是引用的聚合(Aggregation by Reference)。

       明白了合成和聚合关系,再来理解合成/聚合原则应该就清楚了,要避免在系统设计中出现,一个类的继承层次超过3层,则需考虑重构代码,或者重新设计结构。当然最好的办法就是考虑使用合成/聚合原则。

 

4.3 通过合成/聚合的优缺点

优点:

1) 新对象存取成分对象的唯一方法是通过成分对象的接口。

2) 这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的。

3) 这种复用支持包装。

4) 这种复用所需的依赖较少。

5) 每一个新的类可以将焦点集中在一个任务上。

6) 这种复用可以在运行时间内动态进行,新对象可以动态的引用与成分对象类型相同的对象。

7) 作为复用手段可以应用到几乎任何环境中去。

缺点:就是系统中会有较多的对象需要管理。

 

4.4 通过继承来进行复用的优缺点

优点:

  • 新的实现较为容易,因为超类的大部分功能可以通过继承的关系自动进入子类。

  • 修改和扩展继承而来的实现较为容易。

缺点:

  • 继承复用破坏包装,因为继承将超类的实现细节暴露给子类。由于超类的内部细节常常是对于子类透明的,所以这种复用是透明的复用,又称“白箱”复用。

  • 如果超类发生改变,那么子类的实现也不得不发生改变。

  • 从超类继承而来的实现是静态的,不可能在运行时间内发生改变,没有足够的灵活性。

  • 继承只能在有限的环境中使用。

五、 迪米特法则(Law of Demeter,LoD)

5.1 概述

1)定义:一个软件实体应当尽可能少的与其他实体发生相互作用。

     这样,当一个模块修改时,就会尽量少的影响其他的模块。扩展会相对容易。

     这是对软件实体之间通信的限制。它要求限制软件实体之间通信的宽度和深度。

 

5.2 迪米特法则的其他表述

1) 只与你直接的朋友们通信。

2) 不要跟“陌生人”说话。

3) 每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

 

5.3 狭义的迪米特法则

       如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

朋友圈的确定,“朋友”条件:

1) 当前对象本身(this)

2)  以参量形式传入到当前对象方法中的对象

3) 当前对象的实例变量直接引用的对象

4) 当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友

5) 当前对象所创建的对象

任何一个对象,如果满足上面的条件之一,就是当前对象的“朋友”;否则就是“陌生人”。

缺点:会在系统里造出大量的小方法,散落在系统的各个角落。

与依赖倒转原则互补使用

 

5.4 狭义的迪米特法则的缺点:

在系统里造出大量的小方法,这些方法仅仅是传递间接的调用,与系统的商务逻辑无关。

       遵循类之间的迪米特法则会是一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接的关联。但是,这也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。

 

5.5 迪米特法则与设计模式

门面(外观)模式和调停者(中介者)模式实际上就是迪米特法则的具体应用。

 

5.6 广义的迪米特法则

迪米特法则的主要用意是控制信息的过载。在将迪米特法则运用到系统设计中时,要注意下面的几点:

1) 在类的划分上,应当创建有弱耦合的类。

2) 在类的结构设计上,每一个类都应当尽量降低成员的访问权限。

3) 在类的设计上,只要有可能,一个类应当设计成不变类。

4) 在对其他类的引用上,一个对象对其对象的引用应当降到最低。

 

5.7 广义迪米特法则在类的设计上的体现

1) 优先考虑将一个类设置成不变类

2) 尽量降低一个类的访问权限

3) 谨慎使用Serializable

4) 尽量降低成员的访问权限

5) 取代C Struct

       迪米特法则又叫作最少知识原则(Least Knowledge Principle或简写为LKP),就是说一个对象应当对其他对象有尽可能少的了解。

 

5.8 如何实现迪米特法则

迪米特法则的主要用意是控制信息的过载,在将其运用到系统设计中应注意以下几点:

1) 在类的划分上,应当创建有弱耦合的类。类之间的耦合越弱,就越有利于复用。

2) 在类的结构设计上,每一个类都应当尽量降低成员的访问权限。一个类不应当public自己的属性,而应当提供取值和赋值的方法让外界间接访问自己的属性。

3) 在类的设计上,只要有可能,一个类应当设计成不变类。

4) 在对其它对象的引用上,一个类对其它对象的引用应该降到最低。

 

六、 接口隔离原则(interface separate principle, ISP)

6.1 概念

       接口隔离原则:使用多个专门的接口比使用单一的总接口要好。也就是说,一个类对另外一个类的依赖性应当是建立在最小的接口上。     

       这里的"接口"往往有两种不同的含义:一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;另外一种是指某种语言具体的"接口"定义,有严格的定义和结构。比如c# 语言里面的Interface结构。对于这两种不同的含义,ISP的表达方式以及含义都有所不同。(上面说的一个类型,可以理解成一个类,我们定义了一个类,也就是定义了一种新的类型)     

       当我们把"接口"理解成一个类所提供的所有方法的特征集合的时候,这就是一种逻辑上的概念。接口的划分就直接带来类型的划分。这里,我们可以把接口理解成角色,一个接口就只是代表一个角色,每个角色都有它特定的一个接口,这里的这个原则可以叫做"角色隔离原则"。

       如果把"接口"理解成狭义的特定语言的接口,那么ISP表达的意思是说,对不同的客户端,同一个角色提供宽窄不同的接口,也就是定制服务,个性化服务。就是仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来。

       应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。

       这也是对软件实体之间通信的限制。但它限制的只是通信的宽度,就是说通信要尽可能的窄。

       遵循迪米特法则和接口隔离原则,会使一个软件系统功能扩展时,修改的压力不会传到别的对象那里。

 

6.2 如何实现接口隔离原则

不应该强迫用户依赖于他们不用的方法。

1) 利用委托分离接口。

2) 利用多继承分离接口。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




不出城,如何过一个“有内涵”的五一

$
0
0

又到小长假,看看万恶的朋友圈,已有不少人已然开启假日模式,海岛、沙滩、森林、小镇……让没钱没闲的小伙伴们干瞪眼。但别急,我们一起来探讨下,不出城,出门或宅家,都能过一个有文化有内涵的假期。

出门,不出城

1、出门选择之一:文艺风,装腔范

内涵指数:90

Step 1:搜寻所在城市,未曾去过的地儿。抛弃传统景点,以兴趣点为导向,以增强文化意味为指引,如寻找城市特色书店,有味道的咖啡馆;逛博物馆、美术馆,升级艺术品位。

Step 2:圈定目的地,了解背景资料,然后搜寻附近美食。艺术美食两不误。

Step 3:徜徉艺术品前,留下一张艺术品前的流连的背影,秒杀各式海岛椰风。

2、出门选择之二:舌尖上的“吃货走街串巷”

内涵指数:80

让走街串巷变得有格调。寻找城市里的“古早味”,搜寻那些口碑良好的老字号,找一天,搜寻这些老字号,寻找老味道里的感动。

找寻自己的舌尖上的XX市,吃货的内涵,非吃货的你不懂!

不出城,不出门

3、宅家选择之一:高深电影Upgrade文化趣味

内涵指数:100

煲不了《生活大爆炸》的假期,与其失落地哀叹,不如通过一些另类小众的电影来给升级自己的逼格。准备几部电影,非商业化的、冷门而精彩的电影,如基耶斯洛夫斯基的《蓝白红三部曲》;古典且经典的,如欧洲新浪潮时期的电影,戈达尔的《筋疲力尽》、特吕弗的《四百击》。

准备就绪,点上一支蜡烛,关灯,在黑暗中感受大师的杰作,体验剧情的张力,内涵指数爆棚。

4、宅家选择之二:不装逼,无阅读

内涵指数:95

多看几本书,身体跑得太快,让灵魂也跟上吧。即便灵魂跟不上,也不能让装逼的格调落下。

古典是必须的,复古也是可以的。不读古典书籍的话,可看几本复古味道浓烈的书籍,如《祖父的六抽小柜》;或者走走学术路线,翻看文化大师的作品,如福柯、涂尔干等人的作品,走Professional路线。

格调,不能掉!

5、宅家选择之三:日式整理术的"断舍离"

内涵指数:70

近来风靡日本的整理术理念"断舍离":

断=不买、不收取不需要的东西;

舍=处理掉堆放在家里没用的东西;

离=舍弃对物质的迷恋,让自己处于宽敞舒适,自由自在的空间。

趁着假期,整理杂乱的家,清理那些无用的东西,给自己的房间腾出点空间给新鲜的空气,顺便改造凌乱的空间,走走日式时尚,让家更有格调,提高装逼舒适度。

6、不断提升装逼指数

内涵指数:80

心里想着要做的事情很多,却一直没有做?利用这个假期,征服开头。想学乐器?画画?游泳?健身?……现在开始吧,多学一门技能,或是积累一点谈资,让装逼的格调节节攀升。

怎样?“内涵”假期模式启动吧。

(本文来自“21世纪经济报道”微信公众号。)

JavaScript 需要清楚的10件事

$
0
0

文/谢传贵

 

    在学习JavaScript的过程中,最需要搞清楚的10件事是什么?关于这个问题有人在 Quora上给出了的答案。其中提到了一些很有代表性的知识点(坑),但描述比较杂乱。下面我将在他的基础上进行重新编排和解释。希望对你学习 JavaScript有些帮助(为避免文章跑题,以下内容先不考虑ES5的 strict mode):

 

1.  使用关键字var声明变量

 

    要使用一个变量,应该先声明它。在JavaScript中,声明变量非常简单,因为你不用关心它的类型。

 

1function  setLocal () {
2       var  name = 'Tom';
3       alert('the name is '  + name);
4}
5setLocal(); // "the name is Tom"

 

    如果不用var呢?让我们来看一个例子:

 

01var  sex = 'female';
02function  setGlobal () {
03       var  age = '86';
04       name = 'John';
05       sex = 'male'//我们不知函数外也有一个变量sex
06       alert(name + ' is '  + age + ' years old.');
07}
08setGlobal(); // "John is 86 years old."
09alert(name); // "John"
10alert(sex);  // "male"
11alert(age);  // ReferenceError: age is not defined

 

    在 这个例子中,从setGlobal函数外部我们能够访问(可读写)变量name而不能访问变量age。事实上,函数内部使用var声明的变量是局部变量, 只有函数内部能够访问。但由于没有使用var声明变量name,从函数外部也能访问到它 ,这很不安全。同时,事例代码中还试图声明变量sex,仍然由于没有使用var,却无意将外部变量sex的值覆盖了,即污染了其他代码,这更是难以接受 的。

 

    特别地,在使用一个未声明的变量时,程序将会报错;使用一个已声明而未赋值的变量时,或者使用一个并不存在的对象属性时,返回的值是undefined:

 

1var  name;
2var  obj = {};
3alert(name);      // undefined
4alert(obj.prop);  // undefined
5alert(some);      // ReferenceError: some is not defined

 

    总结:在声明一个变量时省去var,这个变量将变成一个全局变量(global variable),你程序的数据直接暴露给了全局,同时也可能覆盖函数外已有的同名变量,对他人代码构成了风险。所以,请一定记得使用关键字var。

 

2.单引号和双引号没有区别

 

    一些传统的后端语言是明显区分单引号和双引号作用的,例如Java里表示字符需要使用单引号,而表示字符串需要使用双引号:

 

1Char ch = 'a';
2String str = "Cat";

 

    然 而JavaScript没有char这样的数据类型,要表示文本数据类型,只能使用字符串(string)。创建字符串直接量最简单的方法是使用一对单引 号或双引号括起来你想表示的字符序列。选择使用单引号还是双引号从语法上没有区别,如果选择单引号,则字符串内部的单引号需要转义,如果选择双引号,则字 符串内部的双引号同理也需要转义。要表示单个字符,须使用长度为1的字符串。例如:

 

1var  name = "She said, \"Who is the president?\"";
2var  desc = 'What\'s that?';
3var  desc = 'e';

 

    基于上面提到的转义关系,我个人比较喜欢使用单引号,这可以减少许多转义的麻烦,尤其是当你的代码中包含HTML代码时。试想如果下面的字符串选用双引号,那将增加很多反斜杠,而且还容易错:

 

1$('div').append('
2error info
3');

 

    同理,如果HTML标签里嵌入JavaScript代码,也一样能减少反斜杠(不过,应尽量少在HTML标签上写JavaScript代码):

 

3.除了null和undefined,一切都像是对象(object)

 

    JavaScript 的变量类型可以分为两类:原始类型(primitive types)和对象类型(object types)。原始类型有5种,分别是数字、字符串、布尔型,以及null和undefined两个特殊值。除了原始类型,其他的一切都是对象类型。除了 null和undefined,其他一切都“像是对象”。为什么说像是对象,因为接下来你会发现原始类型变量也能调用方法或属性,甚至连函数也拥有方法。

 

1function  f () {
2       var  n = 10;
3       alert(n.toString()); // "10"
4}
5f.call(); // f是一个函数,依然能调用方法

    

    我 们看到,n是一个原始类型的值,而f是一个函数,他们都可以调用方法,就像一个对象一样。事实上,在JavaScript中,除了null和 undefined,一切都可以调用方法或属性。这里有一个隐藏的逻辑,那就是当原始类型的变量试图调用方法或属性时,它会被动态地转成其对应的包装对 象。让我们来检测一下:

 

1function  f () {
2       var  n = 123;
3       Number.prototype.toString = function() {
4              return  typeof  this;
5       }
6       alert(typeof  n); //"number"
7       alert(n.toString()); //"object"
8}
9f();

 

 

4.undefined, null, 0, NaN, ''在作为布尔值使用时都代表false

    

    当处于布尔环境时,undefined, null, 0, NaN, ''会被作为false使用,其他的一切作为true使用。

 

1if  (o) {
2  //当o的值不为undefined, null, 0, NaN, '', false时,进入该处 
3}

 

    要注意,这里的字符串是一个长度为1的空字符串。

 

5.使用全等号===

 

    JavaScript中有两个判断相等的运算符:==(一般相等)和===(全等)。一般相等运算符由2个等号组成,使用它进行相等判断时会对运算符两边的值进行类型转换,以使两边类型相同后再进行相等比较。例如:

 

10 == ''   // true
20 == '0'  // true
31 == true   // true
4false  == '0'  // true
5null  == undefined // true
6' \t\r\n '  == 0  // true

 

    正如上面的例子,由于会自动进行类型转换,一些我们直觉不会相等的值也相等了,这些结果大部分时候不是我们想要的。如果你想了解转换规则,推荐你看《ECMAScript. Equality operators.》,不过相当枯燥难记。

 

    全 等运算符由3个连续的等号组成,使用它进行相等判断时不会对运算符两边的值进行类型转换,要满足相等,它不仅要求类型相同,还要求值相同,所以使用全等运 算符时上面的例子一个也不会相等。这里有一个特例,那就是NaN,它是唯一一个不与任何值相等的值,甚至包括它本身,要判断一个值是否等于NaN,你需要 使用全局函数isNaN:

 

1NaN === NaN  // false
2isNaN(NaN)  // true

 

    所以,除非你很确定两个待比较值的类型是一样的,或者你很熟悉类型转换关系,否则我还是劝你使用全等号吧。

 

6.没有块作用域(block scope)

 

    JavaScript 中没有块作用域或类作用域的概念,只有函数作用域,即函数内部定义的变量对于整个函数体以及函数内嵌套的函数都是可见的,而对于函数体外部是不可见的,与 花括号没有什么关系。例如下面的例子中变量i是定义在if条件的花括号代码块中的,我们依然能从花括号外访问:

 

1function  f () {
2       var  c = 1;
3       if  (true) {
4              var  i = 2;
5              alert(c);   // 1
6       }
7       alert(i);  // 2
8}

 

    正是因为JavaScript只有函数作用域,所以我们可以通过函数来模拟实现私有属性。

 

7.变量声明会被提升到当前作用域的顶部

 

    什么意思呢?还是先来看一个例子(参考犀牛书第6版):

 

1var  scope = 'global';
2function  f () {
3       alert(scope);  // "undefined", not "global"
4       var  scope = 'local';
5       alert(scope);  //  "local"
6       var  name = 'country';
7}
8f();

 

    结 合前面的知识,你也许认为函数第一行会打印"global",因为var声明和赋值发生在其后面,而函数外已经有scope变量了。听起来很和逻辑。事实 却是打印了"undefined"。这里涉及一个JavaScript很有趣的现象—提升(hoisting),函数内部声明的所有变量对整个函数作用域 都是可见的,就好像在函数执行时,所有的变量声明会被提升到第一行一样。上面的代码等效于:

 

1var  scope = 'global';
2function  f () {
3       var  scope, name;
4       alert(scope);  // "undefined"
5       scope = 'local';
6       alert(scope);  //  "local"
7       name = 'country';

 

8}

 

 

    所以,在定义一个函数时,请将所有变量声明放在函数的第一行,因为这样的代码比较真实地反映了变量声明的提升现象。同时,即使你已理解了提升现象,但阅读代码的人不一定理解,为了避免困惑,从代码的可阅读性上仍然推荐将所有的变量声明置于函数作用域的顶部。

 

8.函数的参数可以被省略

 

    这个很好理解。函数声明时可以指定形参的个数,但调用时并不强求传参的个数。在调用时,如果对应形参的位置没有给值,则其值为undefined。

 

1function  hello (name, age) {
2       alert('name is : '  + name + ', age is '  + age);
3}
4 
5hello('Anon', 42);  // name is : Anon, age is 42
6hello("Baptiste"); // name is : Baptiste, age is undefined
7hello("Bulat", 24, 42); // name is : Bulat, age is 24

 

9.JavaScript是面向对象的语言,使用原型继承机制

 

    JavaScript是一门面向对象的语言,使用基于原型的继承机制(原型编程),不存在类(class)的概念。使用JavaScript实现继承非常简单。

 

01if  (typeof  Object.create != 'function') { //为低版本JavaScript提供create方法
02       Object.create = function  (o) {
03              function  F() {}
04              F.prototype = o;
05              return  new  F();
06       };
07}
08var  a = { };
09a.foo = 'hello';
10a.do  function  () { alert('do something.'); };
11var  b = Object.create(a);  //对象b继承自对象a
12b.bar = 'crazy';
13b.bar  // "crazy"  b创建了自己的属性bar
14b.foo  // "hello"  b从a继承了属性foo
15b.do();  // "do something." b从a继承了方法do
16b.foo = 'world';
17b.foo  // "world"
18a.foo  // "hello" // b创建了自己的属性foo, 这不会修改a的属性foo
19a.do  function  () { alert('i am a letter.'); };
20b.do();  // "i am a letter." a的方法do被更新,b动态响应了更新。

 

    从 上面这个简短的示例可以看到,对象a直接从对象b继承了属性和方法,并且之后若是a有修改,b也动态更新继承。这个过程没有class什么事,一切都是对 象,按照Douglas Crockford的说法:“还有什么能比这更面向对象的呢?”(What could be more object oriented than that?)

 

10.JavaScript不仅限于浏览器

 

    随着Web的发展,JavaScript在浏览器端可谓春风得意,但JavaScript绝不仅限于浏览器,它还可以用在其他地方,比如最近风头正劲的Node.js就是运行于服务器端的。

 

【嘉年华推荐】

    

    也许你是一位后端工程师,日常使用的语言具有很完善的预检查能力,任何以上提到的语法错误都不会被IDE和编译器放过,但由于JavaScript通常运行在客户端,加上一些历史的原因,它并没有严格的预检查能力,所以良好的编程习惯是很重要的。

 

    要学好一门语言当然不是掌握10点或20条就能做到的,这需要我们持续的学习和实践。若你有更好的建议,欢迎回复补充分享。

 

 

--

微信名称:阿里技术嘉年华

微信号:alibabatech

简介:传播原创高质量的技术内容

 

转自: http://chuansongme.com/n/172780



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



使用HTML5技术控制电脑或手机上的摄像头

$
0
0

移动设备和桌面电脑上的客户端API起初并不是同步的。最初总是移动设备上先拥有某些功能和相应的API,但慢慢的,这些API会出现在桌面电脑上。其中一个应用接口技术就是 getUserMedia API,它能让应用开发者访问用户的摄像头或内置相机。下面就让我展示一下如何通过浏览器来访问你的摄像头,并提取截屏图形。

HTML代码

下面的代码里我写了一部分注释,请阅读:

<!--理想情况下我们应该先判断你的设备上是否
	有摄像头或相机,但简单起见,我们在这里直接
	写出了HTML标记,而不是用JavaScript先判断
	然后动态生成这些标记
--><video id="video" width="640" height="480" autoplay></video><button id="snap">Snap Photo</button><canvas id="canvas" width="640" height="480"></canvas>

在写出上面这些标记前应该判断用户的客户端是否有摄像头支持,但这里为了不那么麻烦,这里直接写出了这些HTML标记,需要注意的是我们这里使用的长宽是640×480。

JavaScript代码

因为我们是手工写出的HTML,所以下面的js代码会比你想象的要简单了很多。

// Put event listeners into place
window.addEventListener("DOMContentLoaded", function() {
	// Grab elements, create settings, etc.
	var canvas = document.getElementById("canvas"),
		context = canvas.getContext("2d"),
		video = document.getElementById("video"),
		videoObj = { "video": true },
		errBack = function(error) {
			console.log("Video capture error: ", error.code); 
		};

	// Put video listeners into place
	if(navigator.getUserMedia) { // Standard
		navigator.getUserMedia(videoObj, function(stream) {
			video.src = stream;
			video.play();
		}, errBack);
	} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
		navigator.webkitGetUserMedia(videoObj, function(stream){
			video.src = window.webkitURL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
	else if(navigator.mozGetUserMedia) { // Firefox-prefixed
		navigator.mozGetUserMedia(videoObj, function(stream){
			video.src = window.URL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
}, false);

一旦判断出用户浏览器支持 getUserMedia,下面就非常简单了,只需要将那个 video元素的 src设置为用户的摄像头视频直播连接。这就是用浏览器访问摄像头需要做的所有的事情!

拍照的功能只能说是稍微复杂一点点。我们在按钮上加入一个监听器,将视频画面画到画布上。

// 触发拍照动作
document.getElementById("snap")
       .addEventListener("click", function() {
	context.drawImage(video, 0, 0, 640, 480);
});

当然,你还可以在图片上加一些滤镜效果….我还是把这些技术放到以后的文章里再说吧。但至少你可以将这个 画布图像转换成一张图片

以前我们需要使用第三方的插件才能从浏览器里访问用户的摄像头,这不免有些复杂。现在只需要HTML5的画布技术和javaScript,我们就能简单快速的操作用户的摄像头。不仅仅还是访问摄像头,而且是因为HTML5的画布技术及其强大,我们可以给图片上加入各种迷人的滤镜效果。现在,在浏览器里用自己的摄像头给自己拍张照片吧!

跨端组件实践 - 移动时代的前端

$
0
0
作者:zswang

跨端组件实践 - 移动时代的前端

上周六在 QCon分享了这个主题,说好的要有文档……

背景

唯一不变的就是变化

从业十多年,互联网的变化非常大:最初使用的电脑只有 8M 内存、32M 硬盘,现在口袋里装的手机已经是 2G 内存、16G 闪存,网络也从 56K 变成了 1.5M+。这个时代的人是幸福的……

这个期间也见证了 Web 时代的繁荣,从 C/S 走到 B/S。

现在无论是邮件、购物还是游戏、社交、工作等等,在电脑上都能找到满意的 Web 应用或站点。

可是这种景象在移动时代并没有看到。

现场小调查:请问你在手机上和 PC 上用什么方式刷微博?

  • 大部分的人不会在 PC 上用客户端刷微博
  • 大部分的人不会在手机上用浏览器刷微博

结论符合预期,先从变化上分析问题

移动互联网发生了什么变化?

屏幕更小

  • 显示区更宝贵,广告区更难摆放
  • 页面布局更讲究,内容主次更为重要

随身携带

  • 24 小时待机
  • 根据地理位置提供更精准的服务

触摸操作

  • 双手很难并行
  • 虚拟键盘没有物理键盘便捷

更丰富的内置设备

  • 前后置摄像头 / 闪关灯
  • 麦克风 / 扬声器
  • 振动器,静音状态也可以知道有消息到达
  • 电子指南针 / 陀螺仪
  • 蓝牙 / WiFi / NFC

离线使用场景

  • 在没有信号
  • 资费不足

没有持久能源

  • 电池需要充电
  • 计算能力和待机时间冲突

设备碎片化 * 特别是 Android各种屏幕尺寸、各种 ROM

移动互联网的变化带来了新的机遇和挑战

机遇

移动市场高速增长

艾瑞咨询数据显示,2013 年中国移动互联网市场规模达到 1059.8亿元,同比增速 81.2%, 预计到 2017 年,市场规模将增长约 4.5倍,接近 6000亿。移动互联正在深刻影响人们的日常生活,移动互联网市场进入高速发展通道。 【查看来源】

挑战

HTML5 / CSS3 技术在移动端受限

What stops developers from using HTML5? 【查看来源】

性能测试

为什么开发者不选择 HTML5 构建移动应用? 前三个原因是:

  • 性能问题,流畅度与 Native 差距较大
  • 硬件接口缺失,不能控制蓝牙、闪关灯、振动、WiFi、 NFC等等
  • 难以集成本地元素,不能使用桌面图标、订阅推送等

这是我们用主流的机型做的性能测试

性能测试

不难看出 Native 和 Web 的性能依旧差距很大,包括主流韩国和国产机型。

人眼刷新率平均是 24 帧 / 秒,低于这个值用户就会感觉到跳帧。

当然这些问题在 PC 时代也碰到过!那时是怎么解决的?

影响前端的技术

通过浏览器扩展本地能力

  • 使用 ActiveX / NPAPI技术
  • 最经典的插件就是 Flash,虽然它已经淡出了移动时代

JavaScript Engine 进化

  • V8 出现后,JavaScript 的性能提升了数倍
  • 结合高性能的引擎 NodeJS 也使 JavaScript 在后端获得了新生

HTML5 / CSS3

  • 扩展了本地能力,如地理定位、录音录像、本地存储等

但这些影响在移动端是有限的

移动时代前端的现状

Flash 不能使用

Adobe 将停止开发移动版 Flash

NPAPI 即将退役

Google 今年开始屏蔽 NPAPI 插件 【查看来源】

浏览器插件可以扩展本地能力的同时,也会带来稳定性和安全性的问题。

怎么解决性能瓶颈和本地能力缺失的问题?

JS Binding,通过 JavaScript 直接调用 Native API

JS Translate,通过编译器将 JavaScript 翻译成 Native 语言

  • 如号称上帝语言的 haXe可以翻译成 Java、JavaScript、C++、PHP 的语言

Native App,直接使用 Native 技术,从头再来

  • 广义的前端就是要面向用户界面和交互
  • 前端技术也有向全端和全栈的发展趋势

选择手游创业的 @大城小胖近期做了一个教学视频,专门介绍 JSBinding 大家可以参考: When iOS loves JS

以上技术可以解决问题,但不能发挥 Web 自然跨端、迭代方便(不同等待漫长的上架时间)的优势

我们还得寻找一些适合自己的方案。

Hybrid 混合应用方案

本地服务,网页通过 HTTP / WebSocket与本地服务通信,使用本地能力

本地服务

  • 在 Android 里写一个不难,参考 NanoHttpd DIY 一个移动版的 HTTP 服务
    • 优势:能够无缝兼容所有浏览器
    • 劣势:通信容易被嗅探和伪造;很难利用 UI 组件

加壳,这是最常用的技术

加壳

  • 有较成熟的框架可以使用,如: Cordova
  • 通过使用和扩展插件,获得本地能力

Google 也有投入 Cordova 的项目 Chrome apps on Android and iOS

本地服务和加壳方式,都能访问本地能力。但后者本地能力在同一个进程里调度,安全性和便利性相对要高。

回到主题,什么是跨端组件?

自动响应端能力的组件

跨端组件示意

  • 受到 响应式网页设计理念的启发,界面布局可以根据运行环境自动响应和调整,那么本地能力也可以这样
  • 如在普通浏览器里使用 HTML5 / CSS3 构造组件,在提供本地能力的环境里使用 Native View 构造组件。
  • 在提供本地能力的环境里,界面会更流畅;在没有本地能力的环境里应用是完整的。

跨端组件解决的问题:

  • 满足 UI 需要局部流畅的需求
  • 满足运行在各种环境的需求

特点

  • 同一套 API
  • 更好地使用运行环境提供的能力

PC 时代也有这样的组件,如: Raphaël一款矢量图组件,在具 VML 的环境里使用 VML,其他环境里使用 SVG,并保持同一套 API。发散一想: jQueryWebUploader(适配 Flash 和 HTML5)也都是自动响应各种运行环境。

成本总是伴随着收益,解决老问题就会带来新的问题

当页面发生滚动时,Native View 怎么和网页元素一起滚动?还有 Reflow时怎么调整 Native View 的位置?

UI 融合的问题

滚动的问题在 Android 中处理比较方便。因为 WebView 继承至:ViewGroup / AbsoluteLayout,我们只需要将 WebView 作为 Native View 的容器就可以搞定这个问题。

Reflow 发生的频率不高,就用了定时器这种简单粗暴的方法

跨端组件研发的步骤

确定需求

哪些组件适合做跨端组件?

计算量大,需要流畅

  • 图册浏览
  • 地图
  • 多媒体播放器
  • 3D渲染
  • 图像识别,二维码识别、手势识别

减少操作步骤,省去授权

  • 录像、录音

HTML5能力增强

  • 地理定位增强,结合 WiFi
  • Canvas 性能增强(参考: FastCanvas

开发环境

天朝的网络大家知道的,主要找一些代理和镜像

设计 API

发现很多前端团队都开始使用和关注 Web Components

在跨端组件的落地上,我们也选择这种方式来提供 API,原因是:

  • 降低学习成本,保留原生 Web 组件的使用方式
  • 降低业务代码维护工作

目前移动端原生还不支持这个标准,还得选用框架适配,如: Polymer

跨端组件 HTML5 示例代码:

<body><div id="mapBox"><light-map width="350" height="400" center="116.404,39.915" zoom="11"></light-map></div></body>

将组件的HTML部分放到需要显示的位置,然后就和普通的Element一样使用:

  • var lightMap = document.querySelector('light-map');可以通过 DOM 树操作
  • lightMap.addEventLister()添加事件
  • lightMap.setAttribute()、lightMap.getAttribute()设置属性

组件开发

Cordova Plugin 开发

plugin.xml 配置需要的权限、JavaScript 命名空间、文件对应的工程目录等待。细节请参考 官方文档

<?xml version="1.0" encoding="UTF-8"?><plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
      id="com.baidu.light.flashlight"
      version="0.2.7"><name>Flashlight</name><description>Cordova Flashlight Plugin</description><license>Apache 2.0</license><keywords>cordova,battery</keywords><repo>https://github.com/zswang/light-flashlight.git</repo><issue>https://github.com/zswang/light-flashlight/issue</issue><js-module src="www/flashlight.js" name="flashlight"><clobbers target="light.flashlight" /></js-module><!-- android --><platform name="android"><config-file target="res/xml/config.xml" parent="/*"><feature name="Flashlight" ><param name="android-package" value="com.baidu.light.flashlight.Flashlight"/></feature></config-file><config-file target="AndroidManifest.xml" parent="/*"><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.FLASHLIGHT" /></config-file><source-file src="src/android/Flashlight.java" target-dir="src/com/baidu/light/flashlight" /></platform></plugin>

我就自己写一个 闪光灯插件实现非常简单,供大家参考

  • JavaScript 关键部分
var cordova = require('cordova'),
    exec = require('cordova/exec');

var flashlight = flashlight || {};

function torch(successCallback, errorCallback) {
    exec(successCallback, errorCallback, 'Flashlight', 'torch', []); // 调用 Native 的提供的方法,指定回调、Native 对应的类名和动作
};

flashlight.torch = torch;
module.exports = flashlight;
  • Android 关键部分
public class Flashlight extends CordovaPlugin {
    private Camera mCamera;
    public boolean execute(String action, JSONArray args,
            CallbackContext callbackContext) throws JSONException {
        if (mCamera == null) {
            mCamera = Camera.open();
        }
        if ("torch".equals(action)) { // 打开手电的动作
            Parameters parameters = mCamera.getParameters();
            parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
            mCamera.setParameters(parameters); 
            callbackContext.success(null); // 回调 JavaScript
        } else {
            return false;
        }
        return true;
    }
}

百度地图 提供了 Android、JS、iOS 三个版本,正好适合用来做 地图跨端组件

  • 地图跨度组件 Cordova Plugin JavaScript 部分
var cordova = require('cordova'),
    exec = require('cordova/exec');

var baidumap = baidumap || {};

/**
 * 初始化
 * @param{Object} options 配置项,显示位置
 * @param{Function} callback 回调
 */
function init(options, callback) {
    exec(callback, function() {
    }, 'BaiduMap', 'init', [options]);
};

baidumap.init = init;

module.exports = baidumap;
  • 地图跨度组件 Cordova Plugin Android 部分
public class BaiduMap extends CordovaPlugin {
    private CallbackContext mCallbackContext = null;

    @SuppressWarnings("unchecked")
    public boolean execute(String action, JSONArray args,
            CallbackContext callbackContext) throws JSONException {
        if ("init".equals(action)) {
            if (args == null) {
                return false;
            }

            JSONObject params = args.optJSONObject(0);
            JSONArray center = params.optJSONArray("center");
            // Native View 在页面中的显示区域
            int left = params.optInt("left");
            int top = params.optInt("top");
            int width = params.optInt("width");
            int height = params.optInt("height");
            String guid = params.optString("id");
            int zoom = params.optInt("zoom");
            createMap(guid, left, top, width, height,
                    (float) center.optDouble(0), (float) center.optDouble(1),
                    zoom);
            mCallbackContext = callbackContext;

        }
        return true;
    }

    private static Handler mHandler = new Handler(Looper.getMainLooper());
    private static Hashtable<String, MapView> mMaps = new Hashtable<String, MapView>();

    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        // 初始化百度地图 Android 版本
        BMapManager baiduMapManager = new BMapManager(webView.getContext()
                .getApplicationContext());
        baiduMapManager.init(new MKGeneralListener() {
            @Override
            public void onGetNetworkState(int state) {
            }

            @Override
            public void onGetPermissionState(int state) {
            }
        });
    }

    public void createMap(String guid, int left, int top, int width,
            int height, float lng, float lat, int zoom) {
        mHandler.post(new Runnable() { // 注意 JavaScript 调用 Native 会在子线程,如果操作 UI 需放到 主线程中
            private String mGuid;
            private int mLeft;
            private int mTop;
            private int mWidth;
            private int mHeight;
            private float mLng;
            private float mLat;
            private int mZoom;

            public Runnable config(String guid, int left, int top, int width,
                    int height, float lng, float lat, int zoom) {
                mGuid = guid;
                mLeft = left;
                mTop = top;
                mHeight = height;
                mWidth = width;
                mLng = lng;
                mLat = lat;
                mZoom = zoom;
                return this;
            }

            @SuppressWarnings("deprecation")
            @Override
            public void run() {
                MapView mapView = new MapView(BaiduMap.this.webView
                        .getContext());
                MapController mapController = mapView.getController();
                GeoPoint point = new GeoPoint((int) (mLat * 1E6),
                        (int) (mLng * 1E6));
                mapController.setCenter(point);
                mapController.setZoom(mZoom);

                float scale = BaiduMap.this.webView.getScale();

                LayoutParams params = new LayoutParams((int) (mWidth * scale),
                        (int) (mHeight * scale), (int) (mLeft * scale),
                        (int) (mTop * scale));
                mapView.setLayoutParams(params);
                BaiduMap.this.webView.addView(mapView); // 大家注意这一句,将 Native View 添加在 WebView 上,自然就响应页面滚动

                mMaps.put(mGuid, mapView);
            }

        }.config(guid, left, top, width, height, lng, lat, zoom));
    }
}
  • Web Component,注意适配 runtime 环境
void function() {
    var instances = {};
    var guid = 0;

    var LightMapPrototype = Object.create(HTMLDivElement.prototype);
    LightMapPrototype.createdCallback = function() {
        var self = this;
        var div = document.createElement('div');
        var zoom = 11;
        var center = [ 116.404, 39.915 ];
        this.setZoom = function(value) {
            zoom = value;
            map.setZoom(zoom);
        };
        this.setCenter = function(value) {
            center = String(value).split(',');
            map.setCenter(new BMap.Point(center[0], center[1]));
        };

        div.style.width = (this.getAttribute('width') || '300') + 'px';
        div.style.height = (this.getAttribute('height') || '300') + 'px';
        this.appendChild(div);

        // 判断当前的运行环境
        var runtime = (typeof cordova != 'undefined')&& (typeof light != 'undefined') // 有可能插件没有安装或者当前版本不支持
                && (typeof light.map != 'undefined') ? 'cordova' : 'browser';

        var map;
        switch (runtime) {
        case 'cordova':
            var obj = div.getBoundingClientRect()
            light.map.init({
                guid : guid,
                center : center,
                zoom : zoom,
                left : obj.left + window.pageXOffset,
                top : obj.top + window.pageYOffset,
                width : Math.round(obj.width),
                height : Math.round(obj.height)
            });

            instances[guid] = this;
            guid++;
            break;
        case 'browser':
            map = new BMap.Map(div); // 创建Map实例
            map.enableScrollWheelZoom(); // 启用滚轮放大缩小
            map.addControl(new BMap.ScaleControl()); // 添加比例尺控件
            map.addControl(new BMap.OverviewMapControl()); // 添加缩略地图控件
            map.centerAndZoom(new BMap.Point(center[0], center[1]), zoom); // 初始化地图,设置中心点坐标和地图级别

            map.addEventListener('moveend', function() {
                var value = map.getCenter();
                center = [ value.lng, value.lat ];
                self.setAttribute('center', center);
                var e = document.createEvent('Event');
                e.initEvent('moveend', true, true);
                self.dispatchEvent(e);
            });
            map.addEventListener('zoomend', function() {
                var value = map.getZoom();
                zoom = value;
                self.setAttribute('zoom', zoom);
                var e = document.createEvent('Event');
                e.initEvent('zoomend', true, true);
                self.dispatchEvent(e);
            });

            break;
        }
        this.map = map;
    };
    LightMapPrototype.attributeChangedCallback = function(attributeName,
            oldValue, newValue) {
        var self = this;
        switch (attributeName) {
        case 'center':
            self.setCenter(newValue);
            break;
        case 'zoom':
            self.setZoom(newValue);
            break;
        default:
            return false;
        }
        return true;
    };
    document.registerElement = document.registerElement || document.register;
    function init() {
        var LightMap = document.registerElement('light-map', {
            prototype : LightMapPrototype
        });
    }
    if (typeof cordova != 'undefined') {
        document.addEventListener('deviceready', init, false); // 等待设备初始化完成
    } else {
        init();
    }
}();

调试

Ripple

  • 这是一款能在浏览器里模拟移动设备的调试工具,包括模拟 GPS、陀螺仪 等本地能力

Weinre

  • 能够在 Chrome 开发者工具里,远程调试的工具
  • 优势:适用各种设备和浏览器
  • 不足:加载之前的状态不能获知、不能断点调试

Remote Debug

  • iOS 6 和 Android 4.4 开始,可以原生适用 Remote Debug
  • Android 4.4 不仅能打断点,而且还能映射 Web UI (Chrome dev 版本才支持)。

另外大家在移动端还用过啥 NB 的调试工具,欢迎留言推荐

安全考虑

用户主动操作才开启重要功能

  • 类似 Flash 里访问剪贴板,需要用户主动 Click 才可以访问
  • 相比弹出个小黄条让用户授权,这种设计体验要好很多

明确提示状态

  • 如:录音和录像时,有明确的状态显示

参考资料

多数人终其一生,都没把他们真正潜能的0.1%用完

$
0
0

多数人终其一生,都没把他们真正潜能的0.1%用完

你知道吗?多数人终其一生都没有把他们真正的潜能的0.1%使用完!

是真的。问题是:人类的潜能是无限的。电脑可能会遇到硬盘已满的情况,而人脑绝对不会。你可以不断地向前推进你的极限,从而大大更高的层次;结果却发现你还没有达到真正价值的一小部分。

更不幸的是,很多人都没有使用自己的真正价值,只把时间精力花费在不值得的任务上。以下是10种定会让你的真实潜能无法挥发出来的方式。

1、停留在过去而不是聚焦于当下

有些人把自己的生活停留在过去。他们抱怨着过去发生的事情,说着他们本该会怎样,而又为什么没能实现的原因。但是,过去就是过去了,不管你花费多少时间思索追悔过去,都不会再改变什么了。把时间花在消沉过去上,就是对你可能性的浪费。

曾经有一段时间,我在思索如果当初做了X而不是Y,如果做了Z而不是Y,那结局会怎样呢?但是,在那之后,我问自己:“这么想能改变什么呢?”我坐着回想过去,但绝对不会对我的生活有丝毫改变和提高。反而,是往前看、动起来才能让我过上真正令我满意的生活。

你想造就什么样的未来?采取什么样的行动才能创造这样一份理想化的未来?你从过去学到了什么?在未来的路上会帮到你吗?发问对答这样的问题能帮你让当下时刻最大化,以便让你把最好的生活向前推进。

2、受困于细节与宏大远景之间

如果你是个完美主义者,你可能会发现自己定期受阻于完美细节。所以,如果你独自一人,我也是。我会花很多时间编辑事实真相,以便让所有事情都完美,都像我想象的那样。比如在我的文章里,我能花上一个多小时的时间寻找完美的照片,以便精确地表述我文章的含义。我能花上数小时的时间改进我的微博和论坛,因此我的读者们能阅读到我完美的经历。

然而我逐渐意识到:把自己所有的时间都花费在细节上,我并没有最好使用时间。根据80/20黄金原则——我们所能达到的80%的结果来自于行动的20%。要试着达到剩下20%以追求100%的完美结果,我们还需要花费80%更多的努力!

有些人会想:我们应该做好一切以达到最好的结果。在同意此话的同时,这话如果脱离了具体的情况情境,是不真实的。比如说,为了给每一个微博文章都配上最好的图片,花多余的时间找最佳照片的行为阻碍了我去完成高附加值的工作,比如谱写新书、或者为自己的读者创造一些心的挑战。把一小时的时间用来增加附加值还是花一小时的时间找相片?毋庸多说。

想着心里的远景,就能帮你意识到做什么值得,什么不值得;这样你就能相应地引导你的能量。

3、让自己受到小事件的影响

有些时候我们会受到恶意批评或者因小挫折而气馁。貌似这些情绪是有正当理由的,但通常这些事件从长期来看是无关紧要的。想知道一件事情是否值得思虑,有一个方法,那就是:“1年中它的影响是怎样的?三年呢?五年?十年?三十年?”

那如果不是,就证明可能不值得的你花费精力去思考这些事情;相反的是,把精力集中在那些从长远看很重要的事情上。

4、自己的困境却怪罪他人

你生活里有没有什么事情是你责怪他人的?你是否在怪罪经济没能让你得到你想要的工作?责怪你的父母遗传给你“肥胖”的基因?老板给你的工作量太多?周围世界缺乏机会?世界没能给你所梦想的生活?

你能过上梦想中的生活的程度取决于你对自己生命负责的程度。当你正经历某事却责怪某人某事的时候,你就是在否认你自己的责任。你把你生命里那部分的权利交给了别人。

比如说,如果你因自己的肥胖而责怪父母,那么你将会继续胖下去,因为在你脑海中这才是你肥胖的原因。除非你为此担负起责任来,要不你就不可能有力量改变现状。当你为自己生活担负起百分百的责任,让它成为你的职业状态,健康,关系状态,经济,友谊等等,那个时候才是你开始实现你梦想生活的时候。

5、抱怨

偶尔把抱怨当做一种发泄的方式是可以的,但如果经常这样的话,就把你变成负磁场了。当你抱怨的时候,你把自己的能量释放到宇宙里。你花费在抱怨上的每一秒钟,原本都是你用来创造梦想生活的一秒钟。与其悲叹,不如思考一下将境遇提升所能采取的行动。如果每次都这么做,都会向你梦想的生活迈进一步。

6、尝试所有事情都亲力亲为

你是哪种什么事情都喜欢自己上手去做的人吗?我也是,但是多年来,我渐渐意识到这种方式阻碍我更多的进步。在尝试完成所有事件的时候,包括那些事实真相,不太重要的细节(见#2),那就意味着你就不能去做那些高一个层次的事情,重要的事情,诸如你最大的目标和梦想。

从授权开始,外包或者去除那些不太重要的任务,放开比例让自己去做一些更重要的事情。这样以来,你将会注意到你自己在效率上的大不同。

7、设定小目标

很多人设定小目标是因为他们畏惧失败。而事实上他们真正害怕的是:他们总是具有实现一切所想的能力,而他们浪费了自己的时间和梦想。你有这世上一切潜力和能力去实现你所想的任何事。别再安于稍许,尽在今天设定好你的最高目标。你得归功于自己。

8、压抑苦恼

压抑情绪莫过于设定了一个最终会自动爆炸的炸弹。每当你掩埋情绪的时候,都在用辎重将自己称量。应对情绪最好的方式是,不管是开心还是不高兴,都把它们放在桌面儿上,面对它们。不要回避你的问题,如果那么做,那就是你在回避你自己。

我发现一个清除情绪辎重的好方法,就是做大脑信息垃圾训练,花上10至15分钟的时间把情绪倾倒在日记里。(www.lz13.cn)试试看,你立马就会感到轻松起来。

9、认为自己不能做

正如亨利·福特所说:“不管你觉得自己是能还是不能——你都是正确的。”世上再没有什么能比我们的信仰更有力的东西了,我们的信仰就是我们用之来看世界的镜头。如果我们认为自己拥有实现梦想的力量,那么同样的,我们的头脑也会自动锁定所有支持这种想法的证据。

10、拖延自己的目标

拖延是埋没自己潜能的最“好”方法。你是否想让自己的目标从不能实现?确定的话,那就拖延吧。

我这辈子从来就没有见过一个开心的拖延者;我所认识的每一个拖拉者通常都有一颗沉重的心,因为内心深处他们是想实现他们的目标的。内心深处他们知道自己打算要实现自己的梦想。

那么,停止拖延吧,首先从确定你激情所在开始,然后从这里开始,只要你做着自己喜爱的事情,那你就绝不会弄错。


作者:u014796991 发表于2014-5-2 9:55:30 原文链接
阅读:0 评论:0 查看评论
Viewing all 15845 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>