4异步编程
1、函数式编程
函数式编程的相关概念
- 函数一等公民 -> Scheme语言 -> Lisp的派生
- 高阶函数
- 高阶函数则是可以把函数作为参数, 或是将函数作为返回值的函数
jsfunction foo(x) { return function () { return x; }; }
- 后续传递风格(Continuation Passing Style)
- 它的结果接收方式,将函数的业务重点从返回值转移到了回调函数中
jsfunction foo(x, bar) { return bar(x); }
- 经典的例子便是数组的sort()方法,以及forEach等等
- 偏函数
- 创建一个调用另外一个部分(参数或变量已经预置的函数)的函数的用法
jsvar isType = function (type) { return function (obj) { return toString.call(obj) == '[object ' + type + ']'; }; }; var isString = isType('String'); var isFunction = isType('Function');
- 指定部分参数来产生一个新的定制函数的形式就是偏函数
2、异步编程优势和难点
- 优势:之前多篇已复述
- 难点:
- 异常处理
- 函数嵌套过深
- 阻塞代码 - sleep()
- 多线程编程(第9章重点叙述)
- 异步转同步
3、异步编程解决方案
通过一下集中思路
事件发布、订阅模式;(代码演示) promise/deferred;(原理分析,与事件比较) 流程控制库(用法和源码分析)
来解决异步
现在来看技术都已经比较过时,es6+后续版本的支持, async await语法糖、Generator 协程(coroutine)已经很好的解决了异步编程的难点,
但是分析这些模块的实现原理,对于模块、思路、代码的演变很有帮助
- 1、事件发布/订阅模式
- 事件监听器模式是一种广泛用于异步编程的模式,是回调函数的事件化,又称发布/订阅模式。
- Node自身提供的events模块
- 它具有addListener/on()、once()、removeListener()、removeAllListeners()和emit()等基本的事件监听模式的方法实现。
- 解耦业务逻辑, 事件发布者无须关注订阅的侦听器如何实现业务逻辑,甚至不用关注有多少个侦听器存在,数据通过消息的方式可以很灵活地传递
- 也是一种钩子(hook) 机制, 利用钩子导出内部数据或状态给外部的调用者
- 如果对一个事件添加了超过10个侦听器, 将会得到一条警告
- 为了处理异常, EventEmitter对象对error事件进行了特殊对待。
- 继承events模块
- 利用事件队列解决雪崩问题
- 多异步之间的协作方案,解决函数嵌套过深
- 接下来分析了EventProxy如何使用这种模式
- EventProxy的原理
- EventProxy的异常处理
- 2、Promise/Deferred模式
- 使用事件的不足, 执行流程需要被预先设定
- Promise/Deferred模式最早出现于Dojo的代码中
- 广为所知则来自于jQuery 1.5版本
- Promises/A
- 这里看到then()方法所做的事情是将回调函数存放起来。
- 为了完成整个流程, 还需要触发执行这些回调函数的地方,实现这些功能的对象通常被称为Deferred, 即延迟对象
- 与事件发布/订阅模式相比, Promise/Deferred模式的API接口和抽象模型都十分简洁。
- 将业务中不可变的部分封装在了Deferred中, 将可变的部分交给了Promise
- Promise是高级接口, 事件是低级接口
- Promise中的多异步协作
- Deferred.prototype.all
- Promise的进阶知识
- Promise的秘诀其实在于对队列的操作
- 支持序列执行的Promise -
promise().then(obj.api1).then(obj.api2)
- 将API Promise化
- 3、流程控制库
- 尾触发与Next
- 需要手工调用才能持续执行后续调用的, 我们将此类方法叫做尾触发, 常见的关键词是next。
- Connect的中间件应用
- async
- 流程控制模块async
- series()串行、parallel()并行、waterfall()依赖处理、auto()自动依赖处理
- Step
- Step用到了this关键字
- 当时思路很新颖,已经有后来async 和 await的雏形了
- eval(Wind.compile("async", function() {}));
- $await();
- Wind.Async.sleep(20);
- 5、其他streamlinejs
4、异步并发控制
解决并发量过大的问题
- bagpipe的解决方案
- 主要通过一个队列来控制并发量
- bagpipe类似于打开了一道窗口,允许异步调用并行进行,但是严格限定上限。
- 考虑拒绝模式(太多就不接受了)、超时控制
- async的解决方案
- parallelLimit
- queue:动态地增加并行任务