我的技术和生活

  • 2013年IT大预言:PC

    神棍之心,人皆有之。最近在看数学之美,简而言之,科学家眼里,一切都能拟合成函数,就看能不能把参数找出来把因数算出来。不过大家还是喜欢凭借直觉做出各种预测,考验自己的判断力。我也准备写几篇日志,分析一下当今IT乃至TMT的趋势,等到明年这个时候翻出来,看看能说对多少。

    (更多…)

  • 诡异BUG之:IE下表单必须提交两次

    做前端遇鬼是常事儿,比如今天,就遇到个:

    1. IE6~10
    2. jQuery 1.8.3
    3. Backbone 0.9.2
    4. HTML5头
    5. 一个Backbone.View,内部有一个formView托管formsubmit事件,根据classaction进行不同的操作,或者验证数据提交表单
    6. 第一次提交,验证通过,return true,没反应
    7. 第二次提交,验证通过,return true,表单提交
    8. 其它浏览器表现正常

    提炼这些Bug描述就花了不少时间,反复Google也没有什么结果。比如,StackOverflow上类似问题的解答是:submit原本不会冒泡,所以应该直接侦听form;但实际上jQuery1.4之后已经支持submit事件的托管了,我的实验也支持这个结果。

    至于导致问题的原因,我还没想明白也没测出来,留着以后再做吧。最后用Hack的方式暂时解决:

    if ($.browser.msie && isIEFirstSubmit) {
      isIEFirstSubmit = false;
      setTimeout(function () {
        form.submit();
      }, 50);
    }

    有了解这个的高人还请不吝赐教。有感兴趣的同学可以去试试:http://www.dianjoy.com/dev/#/user/updateuser

  • 原来早期Android的WebView真的很奇葩

    以前没在Android下做过原生HTML开发,所以一直觉得大家的吐槽很莫名其妙——不同于桌面错综复杂的环境,高度统一的webkit内核浏览器能整出什么幺蛾子来?结果这次遇到了,才发现原来早期Android系统的WebView真的很奇葩。

    先是有一块文字,可能比较长,我就在作容器的div上写样式为overflow:scroll,以为这样就能用手指触摸滚动了,拿来小米1S一试,通过。结果后来同事找来,说他的手机不行。研究半天,在StackOverflow上看到Android 3.0之后才开始支持触摸滚动,想在2.x系统上实现还得自己写JS实现。一看他的手机,2.3.5。OK,写JS嘛,好说。

    事先我已经知道触摸事件的触发机制,所以很自然的就去侦听touchstarttouchendtouchmove。结果,不行,滚不起来。我以为自己记错了,去MDN上查了查,没错;又猜是事件用错了,尝试touchleavetouchcancel,也不行;2.x的系统不能装Chrome,测试也不好搞。后来终于通过输出发现,touchmove只触发一次,然后Google之,原来Android设计的机制就是只触发一次,想要自主控制事件结束的时机只能event.preventDefault()。这……难道touchmove不是对应mousemove么?

    只这两点就花了我不少时间,不知道还有没有其它的坑。反正做完这个需求我不禁感慨,早期Android的WebView真的很奇葩啊。

    PS:这篇博文应该早于上一篇,换言之就是这个时候我为了在本地调试打开了“Emulate Touch Events”开关的。

  • 一个诡异问题的排查

    这个问题本身其实不能称之为问题,记下来只是我觉得排查经历挺典型的,值得分享。

    先说下我的环境:MacOS 10.8.2 + Chrome 23.x + Bootstrap 2.2.1 + jQuery 1.8.2。事情是这样的,我本来在开发一个新功能,顺便把老页面重构一下,貌似一切正常。重构完毕后,我想随手测试一下重构后的页面,发现下拉菜单竟然不能点击了,或者说,点击完全失效了。

    这让我很恐慌,因为类似的重构过程我近段时间来做的不是一次两次,这次我应该没有任何冒险的改动才是。这种情况下出现的Bug,一般都很棘手。于是,我打开以前的某个页面——同样经历了重构,但是通过了测试,并且在一顿时间的使用中完全没有问题——发现里面的下拉菜单同样点击失效了。于是,真正的排查开始了。

    (更多…)

  • INFINITE会阻碍JavaScript数组排序

    如题。代码就是最简单的,一个装满对象的数组根据某个值排序:

    sortArray.sort(function (a, b) {
      return a[key] - b[key];
    });

    开始某些对象的值是NaN,我试了下,排序正常,结果稳定,就没再管。

    今天突然发现排序失败,没有报错,查了半天不见异常,只好下手排查一切可能因素。第一个就是INFINITE,翻找MDN无果,想办法过滤掉,排序正常。

    想来负无穷也会影响,所以先判断除数不能为0 还是很有必要的啊。

  • MySQL 同表复制数据

    MySQL 同表复制数据

    我觉得再这么下去,我真敢说我写过PHP了……

    需求很简单,在同一个表中复制数据。以前的代码是在PHP里先 select *,然后 extract 成变量,再组合成一个大 sql,最后插入。我觉得这样不好,首先要执行两次 sql,其次写那么一大篇 sql 也挺麻烦的。于是研究了下,发现并不复杂,这里总结一下:

    如果是从别的表里导入数据,可以这样写:

    INSERT INTO `table`
    SELECT *
    FROM `table2`
    WHERE `id`=1
    

    如果是同表,并且表里没有主键,这样也好使;但是有主键的话,会被告知主键重复,这个时候就只能把字段都写出来了:

    # 假设表结构为 id, col1, col2, col3
    INSERT INTO `table`
    SELECT NULL, col1, col2, col3
    FROM `table`
    WHERE `id`=1
    

    这里字段的顺序很重要,要参照表的顺序来写(我是用 MySQL Wordbench 连上库,然后用Alert table 看的);不过好处在于,如果我们需要更改其中某个字段的值,只要在 sql 里直接写就好。比如我们复制后想交换后两个字段,或者改变某个字段的值,就可以这样:

    # 假设表结构为 id, name, age, sex
    # 交换age和sex
    INSERT INTO `table`
    SELECT NULL, `name`, `sex`, `age`
    FROM `table`
    WHERE `id`=1
    
    # 更改某字段的值:将复制得到的name加上copy_前缀
    INSERT INTO `table`
    SELECT NULL, CONCAT('copy_', `name`), `age`, `sex`
    FROM `table`
    WHERE `id`=1
    

    id 这种自增的主键,直接插入 NULL 就可以了,MySQL 会自动帮我们补全(如前几段所示)。

    同时插入多条数据也很简单,这样即可:

    # 假设表结构为id, name, age, sex
    # 复制 id<10 的字段,加上copy_标识
    INSERT INTO `table`
    SELECT NULL, CONCAT('copy_', `name`), `age`, `sex`
    FROM `table`
    WHERE `id`<10
    

    实话实说我不太懂MySQL,不过这样写我觉得有几个好处:

    1. 省事儿,可以不再把变量一一抄上
    2. 可以一次复制多条数据
    3. 只执行一行sql,速度应该会更快
  • 使用免费CDN加速JavaScript的加载

    做前端的,基本都会用上各种开源的框架、类库。在项目中引用它们,就可能需要把用到的文件纳入版本库,这样每次类库更新,我们也得跟着更新文件,比较麻烦。而且,我们知道,浏览器对同一个域名下的资源同时加载的数量是有限制的,加载页面时光类库的CSS和JS就得搞半天,整体速度也会被拖累。

    好在很多仁人志士已经提供免费的CDN分流服务,帮助我们托管类库。我用到的主要有这些:

    jQuery

    jQuery流行度毋庸置疑,所以微软和Google都提供了jQuery系列,包括UI和Mobile的CDN,Google的CDN还包括一些其它类库,比如prototype和Mootools等。

    微软:http://www.asp.net/ajaxlibrary/cdn.ashx#jQuery_Releases_on_the_CDN_0

    Google:https://developers.google.com/speed/libraries/devguide

    Bootstrap

    Bootstrap是由来自twitter的两名“Nerd”工程师创建的前端框架,非常棒,刚好覆盖了网站页面所需,组合使用无往不利。BootstrapCDN为我们提供了相应的服务:

    http://www.bootstrapcdn.com/

    Underscore和Backbone

    cdnjs.com 这种业界良心提供了最丰富的CDN资源,还包括了每种类库的官网或者其在github上的链接(好吧,很多时候他们就是一回事儿),我觉得甚至可以把这个站点当成学习的出发点。肉大师项目中用到的Underscore和Backbone就取自这里,感谢他们。

    值得一提的是他们的域名也很好记~

  • JS加分号的理由

    JS加分号的理由

    JavaScript界关于是否应该加分号的争论由来已久。在我看来,这就跟《格利佛游记》中“大头党”、“小头党”一样,纯粹蛋疼,一群衣食无忧的达人,领着一群不明所以的小白战来战去。

    吐槽时间结束。我本来对于分号不是很在意,一般每行都加,函数和条件后面不加。后来学会了“模块化”的写法——即每个逻辑用一个立即执行函数——(function () { // 逻辑主体 })()包裹,就开始混用。一直没遇到什么问题,直到今天是 Ant + Closure Compiler 编译部署肉大师,莫名其妙的挂掉了。排查半天发现是分号的问题。

    原来的代码可能是这个样子:

    // 模块1
    // 前面有若干代码
    var Manager = {
      prop: '',
      method: function () {
    
      }
    }
    
    // 模块2,开头是个立即执行函数
    (function () {
      // 代码
    })()<
    

    经过压缩后变成这个样子:

    // }}(function 那里,会被当成一个函数来执行,于是整体的解析就会出错了
    var Manager = {prop: '',method: function () { // code }}(function () {// 代码})()
    

    这时只要给每个文件的末尾加上分号,就解决了。还有种做法,就是在开头加上分号,很多开源代码也是这样做的:

    ;(function () {
      // code
    })()
    

    如此,便给JavaScript代码写分号添了一个理由。

  • Surface使用心得

    没找到说明,自己摸索了点,记录下来。

    (更多…)

  • 新玩具:微软Surface

    微软第一次放出Surface消息的时候,我就非常期待。无论是造型、外观、Windows8、号称原生的HTML运行环境,都非常吸引我,尤其是充当了键盘的保护套。预售开始,我就迫不及待的在线上订购了;后来得知当天晚上12点首发,如果现场买还送个鼠标,而且选址又是离我家非常近的联想桥苏宁,我立刻决定把线上的退了,然后跑去现场购买。

    (更多…)