jQuery deferred 对象的 promise 方法

jQuery 从 1.5 版本引入了 deferred 对象,这是一个基于 CommonJS Promises/A 的设计,为了方便异步操作,大家都知道,在 js 中,异步代码是非常的多。

这篇博客不是来详细讲解 $.Dererred 的,阮一峰 的博客里有一篇博客详细介绍了这个。但是在这篇博客中,关于 promise() 这个方法的讲解却是错误的,我发现这个是因为我徒弟去学习这个的时候,看了这篇文章,然后我让他给我讲述的时候,发现了这个错误。所以我想写篇 blog 来说明下。

update(2012.1.2):  我针对此问题给一峰发了 email, 他已经针对下面的问题进行了更新,下面的引用来自他最初的版本。现在他博客中对 promise() 的讲解是正确的,如果想了解整个  Deferred 对象,建议直接移步他的博客中学习。同时感谢阮一峰发现的我这篇博客中的一个小错误,最后面的那段代码,现在已经修复。

下面是引用自阮一峰的博客:

这里有两个地方需要注意。

首先,最后一行不能直接返回dtd,必须返回dtd.promise()。原因是jQuery规定,任意一个deferred对象有三种执行状态—-未完成,已完成和已失败。如果直接返回dtd,$.when()的默认执行状态为”已完成”,立即触发后面的done()方法,这就失去回调函数的作用了。dtd.promise()的目的,就是保证目前的执行状态—-也就是”未完成”—-不变,从而确保只有操作完成后,才会触发回调函数。

下面是 jQuery 的官方文档

The deferred.promise() method allows an asynchronous function to prevent other code from interfering with the progress or status of its internal request. The Promise exposes only the Deferred methods needed to attach additional handlers or determine the state (then,donefailalways,pipeprogress, and state), but not ones that change the state (resolverejectprogressresolveWithrejectWith, and progressWith).

也就是说,deferred.promise() 只是阻止其他代码来改变这个 deferred 对象的状态。可以理解成,通过 deferred.promise() 方法返回的 deferred promise 对象,是没有 resolve ,reject, progress , resolveWith, rejectWith , progressWith 这些可以改变状态的方法,你只能使用 done, then ,fail 等方法添加 handler 或者判断状态。

deferred.promise() 改变不了 deferred 对象的状态,作用也不是保证目前的状态不变,它只是保证你不能通过 deferred.promise() 返回的 deferred promise 对象改变 deferred 对象的状态。如果我们这个地方直接返回 dtd,也是可以工作的,.done 的处理函数还是会等到 dtd.resolve() 之后才会执行.

具体在那篇博客的例子, 如果我们把代码改成如下的形式:

var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
    var tasks = function(){
        alert("执行完毕!");
        dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd;
};
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

这样的执行结果和先前返回 dtd.promise 的结果是一样的。

差别在什么地方呢?如果我们把 $.when 的这块的代码改成这样的:

var d = wait(dtd);
$.when(d)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
d.resolve();

我们会发现 alert(“哈哈,成功了!”) 会立即执行,“执行完毕”却需要5秒后才弹出来。

但是如果我们 wait 函数最后是 return dtd.promise() 这里 d.resolve() 就会报错了,因为对象 d 不存在 resolve() 方法。

同样如果我们把代码改成:

var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
    var tasks = function(){
       alert("执行完毕!");
       dtd.resolve(); // 改变deferred对象的执行状态
   };
   setTimeout(tasks,5000);
   return dtd.promise();
};
dtd.resolve();
$.when( wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

我们也可以发现 alert(“哈哈,成功了!”) 会立即执行,因为 dtd 这个 deferred 对象在被传入 wait 之前,已经被 resolve() 了,而 deferred 对象一旦被 resolve 或者 reject 之后,状态是不会改变的。

然后我们再把 $.wait 这块的代码改成:

$.when( wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
dtd.resolve();

我们也会发现 alert(“哈哈,成功了!”); 被立即执行,虽然 wait(dtd) 执行的时候, dtd 还没有被 resolve,而且 wait 方法返回的是 dtd.promise(), 但是 dtd 这个原始的 deferred 对象是暴露在外面的,我们还是可以从外面改变它的状态。

于是,如果我们真的不想让其他代码能改变 wait 方法内部的 deferred 对象的状态,那我们应该写成这样:

var wait = function(){
    var dtd = $.Deferred(); // 新建一个deferred对象
    var tasks = function(){
        alert("执行完毕!");
       dtd.resolve(); // 改变deferred对象的执行状态
   };
   setTimeout(tasks,5000);
   return dtd.promise();
};
$.when( wait())
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

也就是不要把 deferred 直接暴露出来,最后返回 deferred.promise() ,让其他地方的代码只能添加 handler 。

发表在 javascript, Jquery | 留下评论

2011个人总结

在开始写这篇博客的时候,还有20分钟就要到2012了。我觉得我还是需要来总结一下的,仔细回顾一下这一年我做了什么,什么做好了,什么没做好。

首先,打开了一年前这个时间写下的日志, 先看了下希望能做到的事情。第一条,购入一台Mac,这个完成了,在3月份买入的,这个投资现在看来是值得的。第二条,做了,但是做的不够好,开始有意识的节流,但是积蓄还是很少,这个来年继续做吧。第三条,尝试读了心理学的,还尝试读了小说,第一次读完一个长篇小说《1Q84》。第四条,几乎没做,不过在这个夏天,还是通过游泳、瑜伽、普拉提成功减肥10斤左右。第五条,这一年我总共写了8篇博客,太少了。第六条,我还是单身。

这一年,我做了什么呢?现在想起来,好像还真是充满坎坷呢。是本命年的缘故吗?不,我从来不信这个,连红内裤都没穿。这也许就是成长路上必须经历的吧。先是信心满满的开始做一个大项目,和团队合作的很愉快,但是在项目一期快完成的时候,项目却被停了,所有的努力都白费了,和失去了自己心爱的东西是一样的感觉。不过不管怎么样,也是有收获的,比如在技术上的积累,以及认识了一些朋友。

这个半途而废的项目结束之后,就开始做了很长一段时间小需求,还遇到了几个非常不靠谱的人,然后发了几次脾气,被投诉了几次。那段时间还被老大拉去谈话,说我这个要改。哎,我也不想为了这些事情去和别人吵架,但是每次遇到这些不靠谱的人的时候,我就很难忍住,总觉得和他们合作太浪费我的生命了。

不过还好,这样的日子不算太长,接下来由于架构调整,就去做我的阿里这个产品线了。下半年的大部分日子都在做这个,状态不错,主要是这个产品线的其他同事都比较靠谱,和靠谱的人合作,心情和效率都会很不错。接下来还要继续在这个产品线,我也有一些关于这个产品线的前端方面的规划,手头项目忙完,会好好整理一下。

下半年,还有一个项目对我的锻炼也蛮大,是 web IM 项目,这个项目前期,我就想了很多,然后我想根据需求想了一整套设计方案,来适应当前的应用场景和未来的应用场景,然后去给项目组其他成员讲这些,得到了一致认同。不过悲剧的是,项目中途遇到了一些技术难题(主要不是我负责的这块),然后当时很难搞定,就暂停了,这个我也有一部分这人,在项目前期,没有认真考察这些技术的可靠性,就想当然的开始编码了。还好现在这些已经有了进展,不过是其他同事在跟进,我实在是抽不出时间了。

好了,工作上的事情就到此为止,再回顾下生活上有什么进展吧。

首先,到现在我还是单身,好像也从来没怎么去努力摆脱这个现状,这个要批评自己了,2012要好好努力,哪怕世界毁灭,也希望能有一个心爱的人和我一起欣赏最后的风景。

一个人在外,每次有朋友来杭州都特别高兴,今年在杭州还是见了不少朋友,也是你们,让我在杭州的生活增添了不少色彩。

今年去了上海,去了南京,去找老朋友们玩,每次都玩的很开心,和这些老朋友们相聚,总是会回忆起学校的美好时光。遗憾的是,一直说的要去苏州的,甚至有次酒店都定好了,结果由于一些原因没有去,就再也没去过了,现在苗苗都走了,更不会去了。

另外今年还和同事们一起去了徽杭古道,一起去了舟山溗泗,一起去了西塘,每次都玩的很开心,感谢有这么一群可爱的同事们。去徽杭古道让我体验了一下睡帐篷的感觉。去溗泗我第一次下海水游泳,第一次尝到了海水的味道。西塘是我去的第一个江南古镇,虽然我觉得最好玩的是晚上大家在酒店玩狼人。

2012, 我要见更多的老朋友,去更多的地方看看,也要带爸妈来杭州看看。

2012,我要继续减肥,为了自己的健康,希望不再有脂肪肝。

2012,我要阅读更多种类的书籍,来完善自己。

2012,我要学会更合理的消费,开源节流。

2012,我要继续写博客,继续分享我认为值得分享的东西。

2012,我要在技术上精益求精,大胆尝试新技术,让新技术能和产品完美结合起来。

2012,我要学会控制自己的情绪,但是对待事情要同样的认真。

2012,我不要再一直一个人过。

发表在 未分类 | 6 条评论

Mac 在无法启动的情况下备份数据

上周,我的 MBP 悲剧的突然出现了无法启动的情况,启动的时候,出现一个进度条,然后这个进度条走不完,就会被关机。阅读说明书上的方法,先进从 recovery 盘启动,用磁盘工具检查硬盘,可以发现磁盘错误,但是尝试紧急恢复总是失败,然后又尝试用系统盘进入磁盘工具检查硬盘,结果一样,可以看到错误,但是无法修复。这个时候,我决定格式化硬盘重装系统了,但是数据还没备份出来呢,这个时候也没办法进入系统,没办法挂载这块有问题的硬盘。后来经过其他人的提示,想到了 single-user mode ,试了下,还真成功备份出数据来了。不过有一些技巧,下面记录下在 single-user mode 环境下,如果挂载移动硬盘用来转移数据。

1,连接好移动硬盘,然后启动 Mac 到 single-user mode (启动的时候按住 command + s ),记住,一定要在启动前连接好移动硬盘,中途插上,我试了好几次都没成功。

2,按照提示,输入
/sbin/mount -uw /

/sbin/fsck -fy
两个命令用来用读写模式挂载硬盘和检查磁盘。这个时候,如果你的情况和我一样,这个时候 /sbin/fsck -fy 应该会报出错误,但是没关系,接着往下操作。

3,执行
ls /Volumes
这个命令将显示所有被挂载的磁盘,你的移动硬盘或者U盘很可能还没在这里显示,那就说明还没有被挂载。没关系,如果没被挂载,我们先在这里创建一个挂载点。例如:
mkdir /Volumes/usb

4,我们需要确定挂载的移动存储设备的磁盘编号:
ls /dev/disk*
一般情况下,移动存储设备的编号在最后面,例如 /dev/disk1s1

5,现在,挂载移动存储设备到刚才创建的挂载点,执行如下命令:
/sbin/mount_msdos /dev/disk1s1 /Volumes/usb
由于我的硬盘格式是 FAT,如果你使用的硬盘或者U盘格式不是这个,可以在 /sbin/ 这个目录里找到对应的 mount 工具,执行命令。

6,如果挂载成功,你现在可以通过运行:
ls /Volumes/usb
查看移动存储设备内的文件了。

7,可以尝试从机器内的硬盘复制文件到移动存储设备了:
cp /Users/your_user_name/Documents/somefile /Volumes/usb/
如果成功,那么就可以把你的重要数据备份出来了。

这个方式是参考自:http://www.macsage.com/mounting-usb-drive-in-single-user-mode/

另外,如果你有办法在 single-user mode 下搞定网络问题,那么也可以通过 SSH,FTP等方法来备份,single-user mode 下面还是有蛮多的 UNIX 标准工具。

如果你的 Mac 硬盘遇到和我一样的问题,希望这个文章能帮到你。

发表在 未分类 | 4 条评论

WebSocket Protocol 介绍与实现

今天在方凳会上分享了 websocket protocol以及简单实现,PPT 和代码都放出来,有兴趣的可以围观

然后用 python 简单的实现了 websocket server,代码如下。在网上找的很多代码,都不再兼容 websocket draft 10, 因为 websocket 的草案进化太快,下面的代码是按照 draft10 写的。 chrome 14+ , firefox 7/8 都没有问题。

关于 websocket 草案,请阅读 http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10

 

另外推荐一个 Python 的 websocket server http://www.tavendo.de/autobahn/home.html, 基于 twisted 的异步模型。

发表在 javascript, python, WEB | 标签为 , | 留下评论

修复 MOTO milestone 电源键失灵(教程)

教程在后面,请先让我吐会槽 :)

去年9月份买的MOTO Milestone,8月份的时候,突然出现了电源键失灵的情况,按下去没有回馈,机器也没反应,好在Milestone 是有滑盖的,滑开键盘也可以点亮屏幕,完成解锁动作。至于开机,平时很少有这样的需求,万一不小心关机,可以用数据线连接电脑,会激活手机,完成开机。

结果中秋节的时候,去南京找两个朋友完,早上出门后,突然不知道怎么回事关机了,然后由于没有背电脑,就开不了机了,还约了一个高中同学下午见面的,这下才觉得非常不能忍受这个按键坏掉了。想到淘宝上的卖家承诺的一年保修,打算尝试下。

联系了店铺的客服,客服直接让我把手机给他们寄过去维修,态度还蛮好,我就放心的把手机按照规定写好字条给他们寄了过去,大约一周后,收到了寄回来的手机,确实修复了这个按键。但是用了会儿后发现,手机振动失效了,拿下电池观察了下,发现里程碑的振动器是可以从电池仓看到的,发现被一小块海绵堵住了,估计是维修人员技术太次,没注意留在机器里的,我自己用个回形针把它勾出来了,就好了。

修好后第二天,按键又坏掉鸟。。。两天大概按了20次左右吧,因为已经养成解说推开键盘的习惯了。晚上亲眼看见一个金属碗状的原件从手机里掉出来,当时就先把这个原件保存下来,第二天联系售后,售后说肯定是我排线坏了什么的,我说这个按键明显按下去没有回馈了,和好的时候是不一样的,售后说要想修可以再寄回来,费用还是 AA。随后此售后还说我怀疑他们的修理能力,笑话,这种维修质量,智商没问题的人都会怀疑你们吧。我哪儿再敢寄回去呢,于是决定自己动手,丰衣足食。

首先,在网上搜索了下 milestone 拆机图,找到了这个链接 http://moto.zol.com.cn/167/295_1663342.html

当然,要拆掉机器,你肯定需要工具才行,手机的螺丝钉和常见的不一样,需要专业的工具,所以你还需要这样的工具(我这个是很早前买的,就是为了拆各种电子设备的)

有了此工具,你就可以方便的按照上面帖子,开始拆机了,不要被那个拆机教程吓到了,我们只是拆开外壳就可以完成按键的维修了,不需要大卸八块。

拆掉后盖,就可以拿掉所有实体按键了,其实按键的远离很简单,下面板子上有两个未接触起来的触头,实体按键和这个板子中间隔了一个碗状的金属片,按下按键的时候,这个碗状的金属片会把下面两个触头链接起来。

下面是我的维修的时候的图片。

那个黄色的东西就是我说的碗状的金属片了,最后一张图,是正常的音量键上的。找到原因,就好维修了,立马下楼去超市买了双面胶,回来把那个金属片固定在它应该在的位置上,接上电池,测试OK,然后装上后盖,就可以用了。

需要特别注意的地方:电池仓下面的那个喇叭外面的黄色金属条,很软很软哦,小心点拆,我的就被我撕裂了。。。

如果你的那个金属碗状物都找不到了,试试求助淘宝,看看能不能买到这个玩意儿吧。

下次再也不相信淘宝上的 JS了。爆下这个JS的店铺名:南京大学生手机网,下次再也不在这个店铺买了。

 

 

 

 

发表在 生活 | 标签为 , , , | 6 条评论

localStorage in HTML5(2)

上一篇博客简单的介绍了下 localStorage,并且对各个浏览器的存储空间大小做了简单的测试。在上篇博客到这篇博客期间,世界也发生了很多变化,IE9 和 firefox4 正式版都发布了。于是我也对这两个新的浏览器进行了测试,关于 localStorage 的, IE9 和 IE8 表现一致,FF4 和 FF3.6 表现一致,和上篇博客中介绍的一样,FF4 在 Mac 下和 WIN 下表现仍然不一致,参考上篇博客。同时,给出我写的测试存储空间大小的页面,你可以自己来试试:http://lab.allenm.me/html5/storage/maxtest.html

除了最基本的和使用 cookie 一样使用 localStorage,我们还能用它来做什么呢?

如果你看过 localStorage 的文档,你应该注意到了我们在改变 localStorage 中存储的数据的时候,会触发一个 storage 事件:

interface StorageEvent : Event {
  readonly attribute DOMString key;
  readonly attribute any oldValue;
  readonly attribute any newValue;
  readonly attribute DOMString url;
  readonly attribute Storage storageArea;
  void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in any oldValueArg, in any newValueArg, in DOMString urlArg, in Storage storageAreaArg);
};

 

既然我们可以知道此“源”下的localStorage 中的某个字段的值发生了变化,那我们就可以在前端做到跨页面通信,这个是有意义的。 你想想看,在我们目前的WEB应用中,经常会发生这样的事情:在淘宝或者其他电商网站购物,点击购买某个物品,会在页面上购物车中显示。然后在新的 tab 页中打开其他物品的页面,也点击购买,新的页面当然会显示你购买的所有物品,但是旧的页面中的购物车却并不会主动更新这个数据。以前的技术并不是不可以实现这个,只是相对来说成本较大,没有必要。利用 localStorage ,我们就可以只使用前端技术来同步这个数据,成本极小。

我写了一个简单的利用 storage 事件来做前端层面的夸页面数据同步,请在支持 localStorage 的浏览器中打开两个此页面:http://lab.allenm.me/html5/storage/ ,然后在任意一个中输入任意字符,再看看另外一个页面中有什么变化。

我们知道 localStorage 中,我们只可以保存字符串。但是有些时候,我们需要保存一些结构比较复杂的数据,字符串不适合做这种工作,自己再制定一种特殊的规则来利用字符串保存这些数据,也是不明智的选择。因为我们已经有了 JSON 这个事实上的标准了啊。要让 localStorage 支持 JSON 的存储也比较容易,我们只需要自己再封装一层就OK了。现代浏览器已经原生支持 JSON 的解析,JSON.parse() 用来把字符串解析成 JSON 对象,JSON.stringify() 用来把 JSON 对象编码成字符串格式。有了这两个方法,我们只需要在存储的时候,编码,获取数据的时候,解码就可以实现用 JSON 来存储数据了。具体封装这里就不给出代码了。

即使有些不够现代的浏览器不支持 JSON.parse() 和 JSON.stringify() 也没关系,因为我们还有开源的 js 实现的 JSON 的解析器和编码器:老道的 JSON-js

localStorage 还有一个孪生兄弟,叫 sessionStorage,他们的用法基本一致,同属于 WEB Storage, 只是保存的数据的生命周期有区别,详情请阅读这里

发表在 javascript, 未分类 | 标签为 , | 一条评论

localStorage in HTML5(1)

HTML5 中的 localStorage 我相信 web developer 们,都听说过了吧。目前 chrome,firefox,opera,safari, IE8 都支持此属性,注意 IE8 也支持,那就是说,如果你的网站用户不是太低端,起码有一半以上的用户的浏览器是支持 localStorage 特性的。各个浏览器分配给每个“源(region)”的 localStorage 空间至少为 5M(具体数值请看稍后讨论),对于想开始使用 HTML5 的人们来说,这个是个不错的开始。

localStorage 使用方式也非常简单,有 setItem, getItem, removeItem,key, clear 5个方法,和 length 一个属性。定义如下:

interface Storage {
  readonly attribute unsigned long length;
  DOMString key(in unsigned long index);
  getter any getItem(in DOMString key);
  setter creator void setItem(in DOMString key, in any value);
  deleter void removeItem(in DOMString key);
  void clear();
};

localStorage 中都是以 key/value 的形式来存储数据的,存储的数据类型都是字符串,如果需要其他类型,需要自行转换。我们可以使用 setItem 方法来存储数据,例如 localStorage.setItem(‘foo’,'test data’); 这样来存储一个 key 为 foo 的数据,然后可以使用 getItem 来读取 value 值,即 localStorage.getItem(‘foo’); 如果 setItem 的时候,key 已经存在,则修改保存的数据为最新的数据,如果不存在,则新建 key。执行 removeItem() 可以删除已经存储的数据,比如localStorage.removeItem(‘foo’) 可以删除 key 为 foo 的数据。执行 clear() 会清除此“源”下的所有数据。key() 方法可以获取第 n 个数据的 key 值,例如 localStorage.key(0) 可以获取到第 0 个 key/value 对 的 key 值。这个配合 length 属性可以遍历出所有存储的值。length 属性返回已经存储的数据的条数。

上面简单的介绍了下 localStorage 的用法,然后我们来讨论各个浏览器分配了多少空间给 localStorage。

在各个浏览器中,只有 opera 可以清楚的看到用了多少空间,当这个容量到达 5M 的时候,浏览器就会提示用户是否增加容量,如果用户点击了拒绝,那此后就不会再提示,如果不删除这些数据,将不能再存储,抛出错误。如果用户点击了允许,那将获得以前两倍的空间,等到达了新的上限后,又会弹出提示,以 5M -> 10M -> 20M -> 40M 这样递增。

另外 IE8 的 localStorage 对象,有个 remainingSpace 的属性,可以查看剩余的可用空间,在 IE 中执行 alert(localStorage.remainingSpace) 可以看到 IE8 有5M 的最大存储空间。如果达到最大值,会抛出错误,不清除数据前将不能继续存储。

其他浏览器我还没找到办法查看最大容量,但是我用同样的脚本在不同的浏览器里跑,等到达最大值后,查看存储的键值对的数量,结果如下:opera 可以存储 1482 条记录,chrome 和 safari 可以存储1986条,MAC下的 firefox 3.6  可以存储3970条,IE8 下可以存储 3786条。WIN 下的 firefox 3.6 一直没得到结果,一直没有抛出错误,好像是无限的一样。(以上浏览器都是使用的截止到今天的最新的正式版)。 win 下的 firefox 3.6 的问题还有待验证,我使用的环境是虚拟机下的 windows7 系统。

从 IE8 的 remainingSpace 属性可以看出默认最大容量也是 5M ,和 opear 相同,但是存储的条目数量却相差很大,猜测可能是使用了压缩算法,因为存储的都是字符串,压缩率还是非常可观的。chrome 和 safari 具体的最大容量,从这里也没办法推断出来,不过既然 opera 存储的条目数最少,那我们就认为至少可以存储 5M 的数据吧。

有了 5M 这个数量,我们就可以判断哪些数据适合用这个来存储,哪些不适合。毕竟现在如果存储满了后,还没有什么好办法来清除一些不再使用的数据,因为我们从代码里不容易判断哪些是用户很少用到的。最好使用这个 feature 来实现一些用户体验加强的东西,而不是来实现关键性的东西。

另外在 IE8 以下的版本,我们可以使用其他技术来代替,比如 IE 特有的 userData,或者 flash store 。可以考虑封装一下,暴露出统一的接口给用户( developer)使用。

发表在 javascript, WEB | 标签为 , | 5 条评论

2011春运,该怎么买火车票?

又到了年关了,在外辛辛苦苦一年的游子们终于可以回家看看爹娘,看看家乡。可是春运啊,一票难求,那个什么部说的什么时候解决一票难求的新闻,实在是没法让心信,早就不相信此类新闻了。

可是家要回,票要买。那要怎么买呢?我在买火车票前一个星期的时候,写了一个自动抓取 58 同城和百姓网上的转让信息的脚本,然后放在 VPS 上。用 cron 定时每10分钟执行一次,在买票的那两天,我甚至提高到3分钟一次。具体脚本怎么写,我就不说了,没什么技术含量。抓回 HTML 用正则匹配有用的信息,和上次抓回来的比较,有更新,就发个 email 通知就可以了。可是效果怎么样呢?信息获取的到是蛮及时,可是,打过去绝大部分都是黄牛,而且都是低等黄牛,开口就加300 ,票面钱才 300 呢。一到这个时候,58 同城,赶集网,百姓网上的这些转让信息基本全部是黄牛,所以我没有靠这个买到票。不排除有真正是行程原因走不了的,但是一个个的试,太累了。

那怎么办?尝试电话订票吧,现在基本全国各地都开通了电话订票,电话订票也是有技巧的,要在发售时间前10分钟左右打进去才有可能定到票,比如杭州12点发售,那就11.50的时候就打进去,打不进就一直重拨,加上海的区号重播,打进去后,先不要选择,随便按按无关紧要的听听,看准时间,到了12点,马上开始操作订票,我看到有几个老乡这样订到了票。如果你回家的线路不是太紧张,就更容易了,同事有下午4点半打进去定到了卧铺的。我因为各种原因错过了订票的最佳时机,基本20分钟后就订不到武汉方向的了,没有通过此方式定到票。

其实最容易买到票的方法,是找黄牛。。没办法,虽然大家都恨黄牛,但是这个时候,还是黄牛管用啊,要找靠谱的黄牛,每个公司都会流传一些口碑很好的黄牛吧,就找他们就对了,加的钱也不多,票也靠谱,这次我的大多数同事都是这样定到的。

对于上班族来说,去排队买票是最不划算的事情了,大半夜就要去排队,还不知道要排多少个小时,耗时耗体力,不划算,可能还要请假,有请假损失的钱还不如花钱买黄牛票了。

我这次的票,是一个人买的黄牛票,后来买到了时间更合适的黄牛票,然后转手的。

综上所述,买火车票,要多方面行动,电话订票,黄牛票,转让票都要兼顾,有票了不妨先拿下,有更好的可以转手,这个时间的票很好转。另外要多和老乡们交流,一般大公司会有老乡群什么的,大家在一起交流车票信息,有利于找到更靠谱的车票。

什么时候才能解决春运问题,不敢想,还是自己努力挣钱,直接飞机回去吧,不用这么痛苦。

买票搞的身心疲惫,白天的工作时间都用来买票了,现在要开始加班把这些补回来,要不然项目完不成了。真杯具。

发表在 生活 | 3 条评论

chrome.tabs.create 的 callback 不执行?

在写 chrome 插件的过程中,不知道你有没有遇到使用 chrome.tabs.create 创建一个新的 tab,但是这个方法的 callback 却不执行,具体说来,在调试的时候是可以执行的,关掉 chrome  的 DEBUG 工具后,就不可以了。

前几天我也遇到了这个麻烦,可能出现这种问题的情况为:在点击浏览器上插件的图标后,打开一个 popup 的页面,在这个页面里点击某按钮后执行 chrome.tabs.create 方法新建一个新的 tab 页,关掉 DEBUG 工具后,此方法的 callback 函数就无法执行。

我们先来观察这种 popup 的页面的行为,随便找一个会 popup 页面的扩展,点击,让页面弹出,然后你切换下浏览器上已经打开的 tab 页,看看发生了什么?是不是这个 popup 出来的页面会关闭掉?然后在那个扩展上右键,选择“审查弹出内容”,再切换下 tab,发现了什么?是不是这个弹出的页面依然打开?

这就是问题所在了,默认情况下,chrome.tabs.create 创建新的 tab 后,会自动切换到那个新建的 tab,在不打开 DEBUG 工具的情况下,原先弹出的页面会关闭,也就是被 unload 了,页面中 js 的宿主已经不在了,当然也就不会执行 callback 了。那应该怎么办呢?很简单,不切换 tab 就OK了。在 chrome.tabs.create 的第一个参数中,是有个 selected 的可选属性的,把这个属性置为 false,就不会自动切换到新窗口去了。例如下面的代码:

chrome.tabs.create( { url:chrome.extension.getURL('./html/testy.html'), index:(S.tab.index+1), selected:false }, function(tab){
				setTimeout(function(){_send2Spliter(tab); },50 );
});

我的 callback 中,使用了 setTimeout,是因为我遇到的另外一个问题,我需要在新的 tab 打开后,向新的 tab 发送一点数据,但是大部分时候会失败。经过测试,发送数据的程序是执行了,但是 tab 中接收数据的 callback 未能执行。于是猜测,是新的 tab 中的  chrome.extension.onRequest.addListener 还没来得及执行造成的,于是就稍稍延迟下,再发送数据,这样就OK了。

如果你遇到向新建的 tab 中发送数据失败的情况,不妨也试试这个方法。

发表在 javascript, WEB | 标签为 , , | 2 条评论

Hello,2011

2011年的第一天马上就要结束了,和以前一样,现在要做个2010年的总结和对 2011 的展望。

2010年,角色发生了较大的变化,离开了学校,开始了工作。从头开始回忆2010发生的一些点点滴滴吧。

2010年一月份,开始做毕业设计了吧,是一个Android程序,拿到了导师买来的智器Q5,这个算是第一次和Android亲密接触。虽然这个MID很差劲,但是刚拿到手的时候还是觉得很好玩。为了完成毕设,开始看Android的开发文档,开始学习JAVA。同时,因为已经签了前端的工作,而2009年才开始走上前端这个路,所以基础还差的远,所以也利用在学校的这段时间多看看书,买回来了 《javascript 权威指南》,开始看这部大部头。

二月,应该是过年的时候吧,洗澡的时候发现肚子越来越挺了,是该要注意自己的饮食了。同时,寒假的空余时间比较多,可以用来专心看权威指南,在寒假看完了这本书,收获颇丰。

三月-五月,来到了杭州,开始了我的实习生涯,很庆幸有个非常和气的导师,和一群非常热心的同事,这段时间是我感觉进步最快的时间,在师父和同事,特别是邻座的同事的帮助下,从一个菜鸟,到可以独立完成任务。

六月,回学校搞毕设,以及和大家道别。毕设最后我没选择 JAVA,因为对我来说,这东西太不熟悉,用的很别扭,于是,就使用了 PhoneGap 这个框架把 WEB APP 封装成原生 APP。然后很轻松的过了毕设,而且拿到了较高的分数,只是这个时候,什么分数对我来说都是浮云,我只想和大家过完最后一段时间。

六月,是个伤感的季节,喝酒,叙旧,谈自己的心里话,虽然知道有讲不完的话,但是还想尽量多讲点,因为大家都知道以后再见就不容易了。一群爷们,晚上在楼道喝酒,可以喝的个个都嚎啕大哭,大家这四年都有遗憾的事情,大家都有很多事情没来得及,可是,哥们们,人生不可能完美,这我们都知道,擦干泪水,让我们都好好努力吧。

毕业总是有太多太多想说的,一直到最后一天,大家拥抱,挨个送别,知道吗?坐上出租车从学校走的时候,心都要碎了,真想时间能停下来,让我再看看这个学校,再看看这里每个可爱熟悉的面孔。现在回想起来,还是鼻子一阵酸,这是我人生最难忘的回忆。这里也有三篇纪念文(123),相信多年后,翻起来看看,颇有意思。

七月,正式入职了,入职培训,拓展训练是给我印象最深的东西,也给了我很多感触,我也专门写过一篇博文

八月到年末,不断的做需求、项目,然后慢慢的成长。中间在方凳会上分享了3次,这些都是非常高兴的事情,不过分享质量有待提高,以后我也会准备更精彩的内容和大家分享,我喜欢这种氛围,并愿意去为之做点事情。

夏天,和小帅和袁帅见过两次面,在这么远的地方和朋友见面是一件很高兴的事情,尤其是在这个城市,没有一个以前的朋友的时候,这种感觉更是强烈。

十一的时候,苗苗也来杭州玩了,也是同样的感觉,而且特容易勾起关于学校的回忆。元旦,苗苗也在杭州,3号去见面。

最后两个月,获得了提前转正的机会,然后又在 2010 年最后几天,从现在的运营组调到平台产品组。这些都是对我的信任,其实我自己知道,自己的能力还很不够,但是我会一直努力让自己去提高的。这次换组,对我来说挑战蛮大的,新的小组做的产品比运营组做的产品会复杂很多,不过我喜欢这些挑战。

2010年,没有什么积蓄,也只买了一个手机,算是比较大件的东西,开始体会到了生活的不易。

2010年,依然木有女朋友。

好了,该说说我期望的2011 了。

先说说工作上,我依然要在前端开发这条路上走下去,要去学习更多的东西。在这一年,不止从工龄上不再是新人,从能力上,也要摆脱新人,调整好心态,和团队共同进步。同时,要慢慢学会高调做事,低调做人。现在做事和做人都蛮高调 ,要改改了。

工作外的事情:

  1. 买一台新笔记本,现在这台差不多不能用了,最好是 MAC。
  2. 要有一些积蓄,改考虑考虑以后的生活了,不能像现在这样月光,以后怎么样都懒的想。
  3. 多读一些书,不仅仅是技术类的,社科类的也要多读。
  4. 多锻炼身体,每周至少一次(是的,我知道很难,但是我就是要写出来提醒自己)
  5. 每月至少两篇技术博客,多做分享总是对的。
  6. 能获得自己想要的感情。

以上都是最想实现的,相信在这一年我还有很多事情想做,很多短期的,随着当时的环境想做的,我要不拖拉,挨个实现。

写完已经是2011的第二天了,好了,开始为这一年的目标努力了,我会让这一年成为精彩的一年。

发表在 生活 | 9 条评论