当前位置: 首页 > news >正文

JS读书心得:《JavaScript框架设计》——第12章 异步处理

一、何为异步                              

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

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

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

  面对IO操作频繁的场景,异步执行模式可在同等的硬件资源条件下提供更大的并发处理能力,也就是更大的吞吐量。

  但由于异步执行模式打破人们固有的思维方式,并且任务的发起和任务的执行是分离的,从而提高编程的复杂度。

  多线程、多进程均可实现异步模式。

    

二、从回调地狱说起                          

  相信大家都听过“回调地狱”这一让人蛋疼由难以避免的异步执行模式副作用。示例:

复制代码
setTimeout(function(){
  setTimeout(function(){
    setTimeout(function(){
        setTimeout(function(){
        }, 1000)
    }, 1000)
  }, 1000)
}, 1000)
复制代码

  由于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 + 1
  }, 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

 

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

分类: JavaScript
好文要顶 关注我 收藏该文
^_^肥仔John
关注 - 85
粉丝 - 707
+加关注
0
0
« 上一篇: JS魔法堂: Native Promise Only源码剖析
» 下一篇: Java魔法堂:枚举类型详解
posted @ 2015-02-21 22:39 ^_^肥仔John 阅读( 1072) 评论( 0) 编辑 收藏
 
刷新评论 刷新页面 返回顶部
【推荐】超50万VC++源码: 大型工控、组态\仿真、建模CAD源码2018!
【推荐】加入腾讯云自媒体扶持计划,免费领取域名&服务器
ke0108
最新IT新闻:
· 全球第一款量产「屏下指纹」手机:全面屏时代最完美的解锁方式?
· 盘点CES上的电视黑科技: 模块化电视、激光电视、柔性屏幕
· 京东宣布成立三大事业群 打造积木型组织拥抱无界零售变革
· 苏宁宣布重磅福利:“7天无理由退货”线上线下统一标准
· 兴趣降温 安卓厂商无意模仿iPhone X推出3D识别
» 更多新闻...
阿里云C2-1208
最新知识库文章:
· 步入云计算
· 以操作系统的角度述说线程与进程
· 软件测试转型之路
· 门内门外看招聘
· 大道至简,职场上做人做事做管理
» 更多知识库文章...

公告

肥仔John@github
作品:
iScheme—Scheme解释器
 
 
本文转自
^_^肥仔John博客园博客,原文链接: http://www.cnblogs.com/fsjohnhuang/p/4296831.html,如需转载请自行联系原作者

相关文章:

  • 2017-1-6基础
  • nodejs npm常用命令
  • Bootstrap的竞争对手Zurb Foundation
  • centos7部署PaaS平台环境(mesos+marathon)
  • 2016 年度开源中国新增开源软件排行榜 TOP 100
  • c++ 深度优先算法输出树的访问顺序
  • WCF NetTcpBinding Transport安全模式(1)NetTcpSecurity定义
  • 微信公众号开发之网页中及时获取当前用户Openid及注意事项
  • cocos2d基本类介绍 director/scene/layer/sprite
  • TiDB 源码初探
  • 小而合理的前端理论:rscss和rsjs
  • Dell-R730 【Pxe+dhcp+ftp+tftp+Kickstart+CentOs6.6】
  • Bounce(弹走绵羊)lct裸题
  • MyBatis insert 返回主键的方法
  • dede数据库内容替换,去掉文章内容中的img标签
  • 【Leetcode】104. 二叉树的最大深度
  • Computed property XXX was assigned to but it has no setter
  • ERLANG 网工修炼笔记 ---- UDP
  • Hexo+码云+git快速搭建免费的静态Blog
  • k8s 面向应用开发者的基础命令
  • Netty 4.1 源代码学习:线程模型
  • Redis 懒删除(lazy free)简史
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Vue2.x学习三:事件处理生命周期钩子
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 力扣(LeetCode)22
  • 前端技术周刊 2019-01-14:客户端存储
  • 我建了一个叫Hello World的项目
  • 小程序开发中的那些坑
  • 再谈express与koa的对比
  • 中文输入法与React文本输入框的问题与解决方案
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • Linux权限管理(week1_day5)--技术流ken
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • #微信小程序:微信小程序常见的配置传旨
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • (02)Hive SQL编译成MapReduce任务的过程
  • (Forward) Music Player: From UI Proposal to Code
  • (八)Flask之app.route装饰器函数的参数
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (七)c52学习之旅-中断
  • (十) 初识 Docker file
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (译)2019年前端性能优化清单 — 下篇
  • (转载)CentOS查看系统信息|CentOS查看命令
  • . Flume面试题
  • ./和../以及/和~之间的区别
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?