Skip to content

4异步编程

1、函数式编程

函数式编程的相关概念

  • 函数一等公民 -> Scheme语言 -> Lisp的派生
  • 高阶函数
    • 高阶函数则是可以把函数作为参数, 或是将函数作为返回值的函数
    js
    function foo(x) {
      return function () {
        return x;
      };
    }
    • 后续传递风格(Continuation Passing Style)
      • 它的结果接收方式,将函数的业务重点从返回值转移到了回调函数中
      js
      function foo(x, bar) {
          return bar(x);
      }
      • 经典的例子便是数组的sort()方法,以及forEach等等
    • 偏函数
      • 创建一个调用另外一个部分(参数或变量已经预置的函数)的函数的用法
      js
      var 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事件进行了特殊对待。
      1. 继承events模块
      1. 利用事件队列解决雪崩问题
      1. 多异步之间的协作方案,解决函数嵌套过深
    • 接下来分析了EventProxy如何使用这种模式
      1. EventProxy的原理
      1. EventProxy的异常处理
  • 2、Promise/Deferred模式
    • 使用事件的不足, 执行流程需要被预先设定
    • Promise/Deferred模式最早出现于Dojo的代码中
    • 广为所知则来自于jQuery 1.5版本
      1. Promises/A
      • 这里看到then()方法所做的事情是将回调函数存放起来。
      • 为了完成整个流程, 还需要触发执行这些回调函数的地方,实现这些功能的对象通常被称为Deferred, 即延迟对象
      • 与事件发布/订阅模式相比, Promise/Deferred模式的API接口和抽象模型都十分简洁。
      • 将业务中不可变的部分封装在了Deferred中, 将可变的部分交给了Promise
      • Promise是高级接口, 事件是低级接口
      1. Promise中的多异步协作
      • Deferred.prototype.all
      1. Promise的进阶知识
      • Promise的秘诀其实在于对队列的操作
      • 支持序列执行的Promise - promise().then(obj.api1).then(obj.api2)
      • 将API Promise化
  • 3、流程控制库
      1. 尾触发与Next
      • 需要手工调用才能持续执行后续调用的, 我们将此类方法叫做尾触发, 常见的关键词是next。
      • Connect的中间件应用
      1. async
      • 流程控制模块async
      • series()串行、parallel()并行、waterfall()依赖处理、auto()自动依赖处理
      1. Step
      • Step用到了this关键字
      1. wind
      • 当时思路很新颖,已经有后来async 和 await的雏形了
      • eval(Wind.compile("async", function() {}));
      • $await();
      • Wind.Async.sleep(20);
    • 5、其他streamlinejs

4、异步并发控制

解决并发量过大的问题

  • bagpipe的解决方案
    • 主要通过一个队列来控制并发量
    • bagpipe类似于打开了一道窗口,允许异步调用并行进行,但是严格限定上限。
    • 考虑拒绝模式(太多就不接受了)、超时控制
  • async的解决方案
    • parallelLimit
    • queue:动态地增加并行任务