JS读书心得:《JavaScript框架设计》——第12章 异步处理
一、何为异步
执行任务的过程可以被分为发起和执行两个部分。
同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务。
异步执行模式:任务发起后不等待任务执行完成,而是马上执行下一个任务,当任务执行完成时则会收到通知。
面对IO操作频繁的场景,异步执行模式可在同等的硬件资源条件下提供更大的并发处理能力,也就是更大的吞吐量。
但由于异步执行模式打破人们固有的思维方式,并且任务的发起和任务的执行是分离的,从而提高编程的复杂度。
多线程、多进程均可实现异步模式。
二、从回调地狱说起
相信大家都听过“回调地狱”这一让人蛋疼由难以避免的异步执行模式副作用。示例:
setTimeout(function(){
setTimeout(function(){
setTimeout(function(){
setTimeout(function(){
}, )
}, )
}, )
}, )
由于JS是通过异步执行模式来实现多任务并发执行的,因此不可避免地会遇到异步任务连环嵌套的尴尬局面,而回调地狱则是异步任务嵌套的具体表现形式了。
回调地狱不仅造成代码难以维护,并且会加大调试的难度,一言以蔽之——无法避免的蛋疼:(
三、那些舒缓Callback Hell的方案
既然回调地狱如此的不优雅但又无法避免,那么有没有一些减轻痛楚的抽象方式来处理回调呢?
在寻找良药之前,我们需要先了解的是形成回调地狱的原因,从局部看则是在发起异步任务前必须满足某些前置条件,从全局看则是异步执行模式下的流程控制。其实在同步执行模式当中也存在同样的情况,只不过同步执行模式与我们平常思考的方式一致,因此先满足前置条件再执行同步任务则是顺理成章的事情,也没多大的感觉。但到了异步任务当中则成为突出的问题。想一想,如果异步任务A->异步任务B->异步任务C均以前一个异步任务为前置条件,那么它们的关系其实也就是同步执行,但代码表达上却被迫要使用异步编码模式,这种内在关系与表现形式的差异就造就出著名的回调地狱了。
同步执行模式下的流程控制有 if...elseif...else 、 while 和 try...catch..finally 。而我们的终极目标是采用通过的方式来表达异步执行模式下的流程控制。显然在不改变JS语法的情况下这注定是个伪命题。而我们能做的是不断接近而已。
而@朴灵的EventProxy则是其中一个缓解回调函数之痛的工具库。
EventProxy作为一个事件系统,通过after、tail等事件订阅方法提供带约束的事件触发机制,“约束”对应“前置条件”,因此我们可以利用这种带约束的事件触发机制来作为异步执行模式下的流程控制表达方式。
例如,现在需要在任务A和任务B成功执行后才能执行任务C。
/* 同步执行模式 */
try{
var result4A = execA()
var result4B = execB()
var result4C = execC()
}
catch(e){} /* 异步执行模式 */
// 1. 回调函数方式 —— 出现Callback Hell了!
execA(function(){
execB(function(){
execC()
})
}) // 2. EventProxy
var ep = EventProxy.create('a', 'b', execC)
ep.fail(function $noop$(){})
execA(ep.done('a'))
execB(ep.done('b'))
可以看到使用EventProxy时回调函数的数目并没有减少,但回调地狱却不见了(验证了回调地狱不是由回调函数引起,而是由异步执行模式下的流程控制引起的)
但由于EventProxy采用事件机制来做流程控制,而事件机制好处是降低模块的耦合度,但从另一个角度来说会使整个系统结构松散难以看出主干模块,因此通过事件机制实现流程控制必然导致代码结构松散和逻辑离散,不过这可以良好的组织形式来让代码结构更紧密一些。
四、认识Promise
这里的Promise指的是已经被ES6纳入囊中的Promises/A+规范及其实现。使用示例:
var p = new Promise(function(resolve, reject){
resolve("test")
})
p
.then(function(val){
console.log(val)
return val +
}, function(reason){
})
.then(function(val){
console.log(val)
}, function(reason){
})
我是从jQuery.Deferred的promise方法那开始知道有Promise的存在。但Promises/A+到底描述的一个怎样的机制呢?
1. 表象——API
Promises/A+中规定Promise状态为pending(默认值)、fufilled或rejected,其中状态仅能从pending->fulfilled或pending->rejected,并且可通过then和catch订阅状态变化事件。状态变化事件的回调函数执行结果会影响Promise链中下一个Promise实例的状态。另外在触发Promise状态变化时是可以携带附加信息的,并且该附加信息将沿着Promise链被一直传递下去直到被某个Promise的事件回调函数接收为止。而且Promise还提供Promise.all和Promise.race两个帮助方法来实现与或的逻辑关系,提供Promsie.resolve来将thenable对象转换为Promise对象。
2. 流程控制
通过Promise我们可以成功脱离回调地狱。如:
var execAP = Promise.resolve({then:execA})
, execBP = Promise.resolve({then:execB})
Promise
.all(execAP, execBP)
.then(execC)
这也是Promise被大家广泛认识的功能。
3. 信任机制
由Labjs作者编写的《深入理解Promise五部曲》从另一个角度对Promise进行更深刻的解读。当我们需要通过第三方工具库或接口来控制本地功能模块时,则通过Promise建立一套信任机制,确保本地功能模块在可预测的范围内被第三方操控。
而Proimse仅作为库开发者的乐高积木,面对普通开发者则需要提供更高层次的抽象。
五、认识Generator Function
Generator Function是ES6引入的新特性——生成器函数。通过组合Promise和Generator Function我们就可以实现采用通过的方式来表达异步执行模式下的流程控制了!!!
六、相关笔记
《JS魔法堂:jQuery.Deferred(jQuery1.5-2.1)源码剖析》
《JS魔法堂:ES6新特性——GeneratorFunction介绍》
《JS魔法堂: Native Promise Only源码剖析》
七、iPromise
iPromise是我边学异步处理边开发的Promises/A+规范的实现,并且内部已实现了对Generator Function的支持。经过3次全局重构后现处于v0.8.2,我觉得现在的代码结构阅读起来比较流畅,并且API已固定,预计日后就是打打补丁罢了。欢迎大家fork来玩玩 iPromise@github
八、总结
本文为这段时间我对《JavaScript框架设计》——第12章 异步处理的学习和实践汇总,若有纰漏和不足之处请大家指正、补充,谢谢!
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4296831.html ^_^肥仔John
JS读书心得:《JavaScript框架设计》——第12章 异步处理的更多相关文章
- JavaScript框架设计 第14章 动画引擎
easing-js <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
- 偶的《javascript框架设计》终于出版
#cnblogs_post_body p{ text-indent:2em!important; } 历时两年多,我的书终于付梓出版了.应各方面的要求,写软文一篇,隆重介绍一下此书对各位程序员的钱途有 ...
- Javascript框架设计思路图
这个系列的随笔都是关于Javascript框架设计一书的读书笔记(作者是司徒正美),不是本人原创!!! 一.简介: 1.市面上主流的JS框架,大多数是由一个个模块组合而成,模块化是大多数让软件所遵循的 ...
- JavaScript框架设计(三) push兼容性和选择器上下文
JavaScript框架设计(三) push兼容性和选择器上下文 博主很久没有更博了. 在上一篇 JavaScript框架设计(二) 中实现了最基本的选择器,getId,getTag和getClass ...
- JavaScript框架设计(四) 字符串选择器(选择器模块结束)
JavaScript框架设计(四) 字符串选择器(选择器模块结束) 经过前面JavaScript框架设计(三) push兼容性和选择器上下文的铺垫,实现了在某一元素下寻找,现在终于进入了字符串选择器 ...
- JavaScript 框架设计
JavaScript 高级框架设计 在现在,jQuery等框架已经非常完美,以致于常常忽略了JavaScript原生开发,但是这是非常重要的. 所以,我打算写一个简单的框架,两个目的 熟练框架的思想 ...
- JavaScript 框架设计(二)
JavaScript 高级框架设计 (二) 上一篇,JavaScript高级框架设计(一)我们 实现了对tag标签的选择 下来我们实现对id的选择,即id选择器. 我们将上一篇的get命名为getTa ...
- 浅谈JavaScript框架设计
在这个js框架随处乱跑的时代,你是否考虑过写一个自己的框架?下面的内容也许会有点帮助. 一个框架应该包含哪些内容? 1.语言扩展 大部分现有的框架都提供了这部分内容,语言扩展应当是以ECMAScrip ...
- MySQL性能调优与架构设计——第12章 可扩展设计的基本原则
第12章 可扩展设计的基本原则 前言: 随着信息量的飞速增加,硬件设备的发展已经慢慢的无法跟上应用系统对处理能力的要求了.此时,我们如何来解决系统对性能的要求?只有一个办法,那就是通过改造系统的架构体 ...
随机推荐
- 故障排查:是什么 导致了服务器端口telnet失败?
telnet命令的主要作用是与目标端口进行TCP连接(即完成TCP三次握手). 当服务端启动后,但是telnet其监听的端口,却失败了.或者,当服务端运行了一段时间后,突然其监听的端口telnet不通 ...
- Java多线程13:读写锁和两种同步方式的对比
读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...
- 《你必须知道的.NET》读书笔记一:小OO有大智慧
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象 (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...
- 【css3】--四种气泡
在聊天的场景中,聊天内容需要用到气泡修饰,如下图.下面一一讲解. 图片式: 第一个样式是京东客服,气泡的圆角和钩子都是用了图片.使用了一个table组合成了一个圆角的框框.lm样式拼出了钩子. < ...
- Wix 安装部署教程(十二) -- 自动更新WXS文件
上一篇分享了一个QuickWIX,用来对比两个工程前后的差异,但是这样还是很繁琐,而且昨天发现有Bug,目录对比有问题.这次改变做法,完全让程序自动去更新WXS文件,然后再用CCNet去自动编译,这样 ...
- Android Studio 1.0.1 + Genymotion安卓模拟器打造高效安卓开发环境
我们开发安卓大多是使用Eclipse和安卓SDK中自带的安卓模拟器.当然,Google早就推出了自己的安卓开发环境——Android studio,在不久前,Google发布了Android Stud ...
- 浅谈Excel开发:二 Excel 菜单系统
在开始Excel开发之前,需要把架子搭起来.最直接的那就是Excel里面的菜单了,他向用户直观的展现了我们的插件具有哪些功能.菜单出来之后我们就可以实现里面的事件和功能了.Excel菜单有两种形式,一 ...
- Winform文件下载之WebClient
最近升级了公司内部使用的一个下载小工具,主要提升了下面几点: 1. 在一些分公司的局域网中,连接不上外网 2. 服务器上的文件更新后,下载到的还是更新前的文件 3. 没有下载进度提示 4. 不能终止下 ...
- Visual Studio 2015速递(1)——C#6.0新特性怎么用
系列文章 Visual Studio 2015速递(1)——C#6.0新特性怎么用 Visual Studio 2015速递(2)——提升效率和质量(VS2015核心竞争力) Visual Studi ...
- EF架构~关于多对多关系表无法更新与插入的问题
回到目录 在EF里,我们设计模型时,会设计到多对多关系,在EF里会把这种关系会转成两个一对多的关系表,这是比较友好的,因为多对多来说,对于业务本身没什么意思,所以隐藏了,没什么坏处,但对于这个隐藏来说 ...