这篇读书笔记的主要内容是在家里用ipad上输入的,感觉输入还是比较吃力呀。
本书的副标题是Build More Responsive Apps with Less Code, 关键词是异步、响应式,主要是对如何书写异步js代码提供一些指导意见,描述js的异步特性,回调代码的书写,还介绍了PubSub、Promises等通用模式。 最后介绍了worker多线程模型,js异步加载等内容。书的页数可谓少得可怜,内容还算比较实在, 提供了大量的开源库实现供读者参考,对于框架选型的话倒是可以参考一下。
js事件
主要是了解事件背后的本质。提供了象setTimeout document.onready都是事件的典型案例。 因为js基本都是单线程模型,所以事件的触发和代码的执行有时候并不一致,而是有些时间差。即使是setTimeout(fn,0)这样的代码。 这样的逻辑也不是立即执行的。它的执行模型大概是这样的(在ipad上手绘的)。
任何回调方法的执行都是需要按队列顺序来执行。如果当前代码没有执行完,就不会执行其他回调方法。 因此理解js的异步处理模型非常重要,代码应该尽快执行完毕,避免阻塞其他代码的执行。
哪些是异步逻辑
主要是一些io操作。例如
- ajax调用
- webkit里边的console.log
- dom操作,浏览器可能会延迟的效果出现
- Node服务端里边比比皆是
当然还有些是时间片操作。例如
- setTimeout或setInterval
- node的process.nextTick
- html5提供的requestAnimationFrame等特性
异步逻辑注意
如果使用回调方法进行异步处理,就不要在后面的代码中按同步的逻辑来考虑。
异步回调方法中用到的对象也应该先定义,避免由于缓存等造成奇怪的问题。
可以使用web worker api或异步调用来生成缓存数据。
避免超过两层的回调方法。
处理错误
使用异步调用时,stack trace可能会不全
使用异步调用时,try-catch可能会失效
使用err来作为回调方法的参数,或者区分success和error的回调方法
处理uncaught异常,可以使用:
# Broswer
window.onerror = function(err){
}
# Node
process.on('uncaughtException', function(err){
})
流程控制
回调方法太多,流程控制变得异常困难,很容易造成错误,应该避免超过两层的回调方法。 比较常用的办法有PubSub、Promises等解决方案/模式。
PubSub
就是publish/subscribe,发布订阅,常见的监听器模式。通常是把回调方法组织为带名字的事件,模拟事件触发。例如
- Node的EventEmitter
- Backbone的Event模型
- jQuery的自定义事件
需要注意的是,PubSub模式的逻辑不一定是异步的。 如果trigger是同步逻辑,应该注意避免在回调方法中再次trigger某个事件而造成死循环, 例如jQuery就可能出现这个问题,而像backbone在值没有变化时不再触发change事件,也提供了slient的选项。而Ember之类是采用setTimeout的方式 加入队列进行处理的方式,就是采用了异步的方式。
Promises
书中主要使用了jquery做例子,显示了deferred的用法,对callback的用法有个比较。 熟悉jquery的童鞋通过Deferred的用法就有个大体的印象了。我个人的感觉就是,Promises模型是对PubSub常用功能的抽象, 有点规范的意思,事实上也的确有commonjs的Promises/A规范。
介绍了promises和deferred的区别,deferred是promises一个子集,它不能自己控制状态变更,需要有由其他事件出触发。 对于node来说,现在是采用回调方法的方式,要采用deferred方式,主要做些改变。例如:
deferredCallback = function(deferred) {
return function(err) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(Array.prototype.slice.call(arguments, 1));
};
};
}
var fileReading = new $.Deferred();
fs.readFile(filename, 'utf8', deferredCallback(fileReading));
Async.js
介绍了async.js的用法,用来解决异步处理中的流程控制问题,例如iterator的问题。包括串行和并行的控制。 这个库还提供了更加复杂的并发性控制。具体的用法还是看官方的介绍吧。还提供了另外一个库step的介绍
Worker
提供worker的功能,在浏览器上worker还是有一些受限制的地方,例如不能涉及DOM。 而在node上,可以用cluster来支持类似worker的功能。
异步加载js
主要探讨了几种方案,如在head加载,缺点是页面显示太慢。在body末尾加载,问题是还是要等js结束还能让事件生效,并且同样需要顺序加载。 解决方案有defer/async和ajax加载等方案。
对于比较现代的浏览器,支持defer关键字用于异步js加载,还有async关键字,区别是后者不会顺序加载,先加载完先处理。 async在有些插件化的js时async可能可以用到,其他就很难用到,因为很多js都是存在依赖的关系。
当然,还有一些介绍了自定义的异步加载方案,如html5对象有onready事件,还有ajax加载方式。 不过业界已经有些比较成熟的异步加载库了,如yepnope
最后还介绍了一些异步加载的其他方案,例如增强的语法来支持异步逻辑。这种预编译的方式,我感觉不如在coffeescript上增加关键字的预处理方式, 类似coffeescript的class关键字。另外还介绍js1.7关于异步逻辑的新特性:Generator。