一、何为异步                              

执行任务的过程可以被分为发起和执行两个部分。

同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务。

异步执行模式:任务发起后不等待任务执行完成,而是马上执行下一个任务,当任务执行完成时则会收到通知。

面对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魔法堂:剖析源码理解Promises/A规范

前端翻译:Promises/A+规范

JS魔法堂:jsDeferred源码剖析

JS魔法堂:jQuery.Deferred(jQuery1.5-2.1)源码剖析

JS魔法堂:mmDeferred源码剖析

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章 异步处理的更多相关文章

  1. JavaScript框架设计 第14章 动画引擎

    easing-js <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  2. 偶的《javascript框架设计》终于出版

    #cnblogs_post_body p{ text-indent:2em!important; } 历时两年多,我的书终于付梓出版了.应各方面的要求,写软文一篇,隆重介绍一下此书对各位程序员的钱途有 ...

  3. Javascript框架设计思路图

    这个系列的随笔都是关于Javascript框架设计一书的读书笔记(作者是司徒正美),不是本人原创!!! 一.简介: 1.市面上主流的JS框架,大多数是由一个个模块组合而成,模块化是大多数让软件所遵循的 ...

  4. JavaScript框架设计(三) push兼容性和选择器上下文

    JavaScript框架设计(三) push兼容性和选择器上下文 博主很久没有更博了. 在上一篇 JavaScript框架设计(二) 中实现了最基本的选择器,getId,getTag和getClass ...

  5. JavaScript框架设计(四) 字符串选择器(选择器模块结束)

    JavaScript框架设计(四) 字符串选择器(选择器模块结束) 经过前面JavaScript框架设计(三) push兼容性和选择器上下文的铺垫,实现了在某一元素下寻找,现在终于进入了字符串选择器 ...

  6. JavaScript 框架设计

    JavaScript 高级框架设计 在现在,jQuery等框架已经非常完美,以致于常常忽略了JavaScript原生开发,但是这是非常重要的. 所以,我打算写一个简单的框架,两个目的 熟练框架的思想 ...

  7. JavaScript 框架设计(二)

    JavaScript 高级框架设计 (二) 上一篇,JavaScript高级框架设计(一)我们 实现了对tag标签的选择 下来我们实现对id的选择,即id选择器. 我们将上一篇的get命名为getTa ...

  8. 浅谈JavaScript框架设计

    在这个js框架随处乱跑的时代,你是否考虑过写一个自己的框架?下面的内容也许会有点帮助. 一个框架应该包含哪些内容? 1.语言扩展 大部分现有的框架都提供了这部分内容,语言扩展应当是以ECMAScrip ...

  9. MySQL性能调优与架构设计——第12章 可扩展设计的基本原则

    第12章 可扩展设计的基本原则 前言: 随着信息量的飞速增加,硬件设备的发展已经慢慢的无法跟上应用系统对处理能力的要求了.此时,我们如何来解决系统对性能的要求?只有一个办法,那就是通过改造系统的架构体 ...

随机推荐

  1. 团队项目——站立会议DAY12

    第十二次站立会议记录: 参会人员:张靖颜,钟灵毓秀,何玥,赵莹,王梓萱 项目进展: 1.张靖颜:已经将部分代码完成,对一些模块化的功能进行扩展,对已具备的功能进行完善. 2.钟灵毓秀:对代码进行了修改 ...

  2. 在MVVM模式中,按钮Click事件的绑定方法

    在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的 ...

  3. html5 css3实现图中结构

    <!DOCTYPE html> <html lang="en" > <head> <title>demo</title> ...

  4. AngularJS快速入门指南18:Application

    是时候创建一个真正的AngularJS单页面应用程序了(SPA). 一个AngularJS应用程序示例 你已经了解了足够多的内容来创建第一个AngularJS应用程序: My Note Save Cl ...

  5. php版的redis操作库predis操作大全

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/146.html predis是php连接redis的操作库,由于它完全使用 ...

  6. Eclipse 工程迁移到 Android Studio

    目标:迁移成功,并成功正常运行! 附加:同步视频在文章后面! 两种方式: 1. 用Gradle导出,在Android Studio中用Gradle导入 (不推荐) 2. 用Android Studio ...

  7. Atitit 编程语言常用算法attilax总结

    Atitit 编程语言常用算法attilax总结 1. 编译算法分类and   数据操作算法.1 1.1. Tab driver stat  状态转换表格算法1 1.2. Nest case 词法分析 ...

  8. Atitit 异常的实现原理 与用户业务异常

    Atitit 异常的实现原理 与用户业务异常 1.1. 异常的实现原理1 1.2. 用户业务异常1 1.3. 异常转译和异常链2 1.4. 避免异常2 1.5. 异常恢复3 1.6. catch代码块 ...

  9. Mysql 函数分类

    比较重要的 1 REVERSE(s)    将字符串s的顺序反过来 2 TRIM(s)          去掉字符串s开始和结尾处的空格 一.数学函数  数学函数主要用于处理数字,包括整型.浮点数等. ...

  10. java实现栈与队列

    一.栈 栈是一种特殊的线性表.其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行.(先进后出) 访问权限:栈限制了访问权限,只可以访问尾节点,也就是最后添加的元素 即栈顶的元素 /** * ...