• 《深入浅出Node.js》第4章 异步编程


    @by Ruth92(转载请注明出处)

    第4章 异步编程

    Node 能够迅速成功并流行起来的原因:

    • V8 和 异步 I/O 在性能上带来的提升;
    • 前后端 JavaScript 编程风格一致

    一、函数式编程

    1. 高阶函数

      定义:是指把函数作为参数,或是将函数作为返回值的函数。

      应用:事件处理,数组的迭代和归并方法等。

    2. 偏函数用法

      偏函数用法:是指创建一个调用另外一个部分(参数或变量已经预置的函数)的函数的用法。

      偏函数:通过指定部分参数来产生一个新的定制函数的形式就是偏函数。

      var toString = Object.prototype.toString;

       // 原来,可扩展性不高
       var isString = function(obj) {
           return toString.call(obj) == '[object String]';
       };
       
       var isFunction = function(obj) {
           return toString.call(obj) == '[object Function]';
       };
       
       // 偏函数用法
       var isType = function(type) {
           return function(obj) {
               return toString.call(obj) == '[object' + type + ']';
           };
       };
       
       var isString = isType('String');
       var isFunction = isType('Function');
      

    二、异步编程的优势与难点

    1. 优势

      最大特点:基于事件驱动的非阻塞 I/O 模型。可以使 CPU 与 I/O 并不相互依赖等待,让资源得到更好的利用。

      Node 实现异步 I/O 的原理:利用事件循环的调度方式,JavaScript 线程像一个分配任务和处理结果的大管家,I/O 线程池里的各个 I/O 线程都是小二,负责完成分配来的任务,小二与管家之间互不依赖,所以可以保持整体的高效率。

      事件循环模型的缺点:管家无法承担过多的细节性任务,否则,会影响任务的调度,从而降低整体效率。

    2. 难点

      • 难点1:异常处理;
      • 难点2:函数嵌套过深;
      • 难点3:阻塞代码;
      • 难点4:多线程编程;
      • 难点5:异步转同步

    三、异步编程解决方案

    1. 事件发布/订阅模式

      即事件监听器模式,被广泛用于异步编程的模式,是回调函数的事件化。

      ps:其本身并无同步和异步调用问题,只不过在 Node 中多半是伴随事件循环而异步触发的。

       // 订阅:高阶函数的应用
       emitter.on('event1', function(message) {
           console.log(message);
       });
       
       // 发布
       emitter.emit('event1', 'I am message!');
      

      事件发布/订阅模式可以实现一个事件与多个回调函数(事件侦听器)的关联。

    2. Promise/Deferred模式:包含 Promise 和 Deferred

      ☊ 使用事件的方式:执行流程需要被预先设定。

       $.get('/api', {
       	success: onSuccess,
       	error: onError,
       	complete: onComplete
       });
      

      ♤ Promist/Deferred:可以先执行异步调用,延迟传递处理。这样即使不调用 success()error()等方法,Ajax 也会执行。

       $.get('/api')
           .success(onSuccess)
           .error(onError)
           .complete(onComplete)
      

      ♧ 在原始的 API 中,一个事件只能处理一个回调,而通过 Defferred 对象,可以对事件加入任意的业务处理逻辑。

       $.get('/api')
           .success(onSuccess1)
           .success(onSuccess2)
      

      ☛【Promises/A

      图4-4 Promise的状态转化示意图

      在 API 的定义上,一个 Promise 对象只要具备 then() 方法即可。要求如下:

      • 接受完成态、错误态的回调方法。在操作完成或出现错误时,将会调用对应方法。

      • 可选地支持 progress 事件回调作为第三个方法。

      • then() 方法只接受 function 对象,其余对象将被忽略。

      • then() 方法继续返回 Promise 对象,以实现链式调用。

          then(fulfilledHandler, errorHandler, progressHandler)
        

      图4-5 状态和方法之间的对应关系

      ☛【Promises 和 Deferred 的差别

      Deferred 主要是用于内部,用于维护异步模型的状态;Promise 则作用域外部,通过 then() 方法暴露给外部以添加自定义逻辑。

      图4-6 Promise和Deferred整体关系示意图

      与事件发布/订阅模式相比,Promise/Deferred 模式的 API 接口和抽象模型都十分简洁。它将业务中不可变的部分封装在了 Deferred 中,将可变的部分交给了 Promise。

      Promise 是高级接口,事件是低级接口。低级接口可以构成更多复杂的场景,高级接口一旦定义,不太容易变化,不再有低级接口的灵活性,但对于解决典型问题非常有效。

      ☛【Promises 中的多异步协作

      all() 方法:将两个单独的 Promise 重新抽象组合成一个新的 Promise。

      只有所有异步操作成功,这个异步操作才算成功,否则有一个异步操作失败,整个异步操作就失败。

      ☛【Promises 的进阶知识

      要让 Promise 支持链式执行,主要通过以下两个步骤:

      (1)将所有的回调都存到队列中;

      (2)Promise 完成时,逐个执行回调,一旦检测到返回了新的 Promise 对象,停止执行,然后将当前 Deferre 对象的 promise 引用改变为新的 Promise 对象,并将队列中余下的回调转交给它。

    3. 流程控制库

    四、异步并发控制


  • 相关阅读:
    动态投影
    我的比较差的初级的研究成果
    我最近的研究成果(IGeometry.Project and IGeometry.SpatialReference)
    mysql中的数据类型以及常见约束
    面向对象——多态
    java基础
    java中的异常(3)
    mysql中的数据类型
    面向对象——继承
    java中的异常(2)
  • 原文地址:https://www.cnblogs.com/Ruth92/p/5887510.html
Copyright © 2020-2023  润新知