异步编程

November 18, 2017

  • 函数式编程

    • 高阶函数:JavaScript中函数式一等公民,可以作为参数传递,或者作为返回值返回
    • 偏函数:指创建一个调用另一个部分-参数或变量已经预置的函数-的函数的用法
    var isType = function(type) {
        return function(obj) {
            return Object.prototype.toString.call(obj) === ['Object' + type]
        }
    }

    由上诉代码可知,这种通过指定部分参数来产生一个新的定制函数的形式就是偏函数。这样就不用挨个去实现isFunction()、isString()这样的函数,只需要在isType函数传入参数即可得到定制函数

    异步编程的优势和难点

    优势

    利用事件循环的方式,JavaScript线程像一个分配任务和处理结果的大管家,I/O线程池里的各个I/O线程都是小二,负责兢兢业业地完成分配来的工作,小二与管家互不依赖,所以可以保持整体的高效率。这个模型的缺点在于管家无法承担过多的细节性任务,如果承担过多,则会影响到任务的分配和调度,管家忙个不停,小二却没有活干,这样效率就会降低。Node是为了解决编程模型中阻塞I/O的性能问题的,采用了单线程模型,这导致Node更新一个处理I/O密集问题的能手,cpu密集型则取决于管家能耐。由于海量请求同时作用在单线程上,需要防止任何计算耗费过多的cpu时间片。所以无论是I/O密集型还是计算密集型,只要计算不影响异步I/O的调度,都不会有问题。所以可以将海量计算分解为诸多小量计算,通过setImmediate()进行调度。

    难点

    • 异常处理:不能像同步代码那样使用try…catch,因为异步I/O分为两步,提交请求,和处理结果。try…catch只能捕获提交请求这个阶段的错误(只能捕捉当前这个事件循环的错误),因为处理结果(回调函数的执行)是在下一个事件循环才会执行,try…catch捕捉不到callback执行时抛出的异常。

    在Node中,我们在处理异常时形成了一种规定,会将异常放在回调的一个实参传递,如果不为空,则说明有异常。

    • 函数嵌套过深:多个异步调用
    • 多线程编程:单线程无法高效利用多核cpu的服务器,因为单个Node进程实质上没有充分利用多核cpu。web workers。

    异步编程解决方案

    事件发布/订阅模式

    依赖于Node自身提供的event模块,回调函数事件化。Node对事件的发布订阅机制做了一些小的限制。比如说对一个事件添加的侦听器不能超过10个(这个限制也可以自己修改)为了防止内存泄漏以及过多占用cpu

    Promise/Deferred模式

    这种模式可以先执行异步调用,延迟传递处理函数。这种方式比预先传入回调更好看一些。在原始API里一个事件只能处理一个回调,而通过deferred对象,可以对事件加入任意的业务处理逻辑。CommonJS的Promise/A就是这种模式的一种实现。

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

    流程控制

    async
    • async.series():异步的串行执行
    • async.parallel():异步的并行执行
    • async.waterfall():异步调用的依赖处理

Profile picture

Written by Colgin who lives and works in China, focus on web development. You can comment on github