Skip to content

Instantly share code, notes, and snippets.

@loskael
Last active October 25, 2016 08:58
Show Gist options
  • Save loskael/1af0839b70d78baf0c24 to your computer and use it in GitHub Desktop.
Save loskael/1af0839b70d78baf0c24 to your computer and use it in GitHub Desktop.
JavaScript 异步编程

JavaScript 异步编程

异步模式在web编程中变得越来越重要,对于Javscript来说,异步编程要解决的问题有两个:一是必须通过回调函数进行返回值的处理,另一个是复杂情况下会造成嵌套过深

目前,解决异步流程控制问题的主流方案有以下几种: ##1. 基于回调 适用于流程简单的情况,当出现过多回调的时候实现起来不是很利索,且容易使代码的可读性可维护性下降。

    var done = function(){
        console.log("done");  
    };
    var fail = function(){
        console.log("fail");
    };
    // 通过参数的方式 传入回调函数并执行
    var run = function(done, fail) {
        setTimeout(function(){
            Math.random() > 0.5 ? done() : fail();
        }, 1000);
    };
    
    run(done, fail);

##2. Promise/Deferred 可以参考 这里

    // 以 jQuery 为例
    var wait = function() {
        // 新建一个deferred对象
        var dfd = $.Deferred();
        var run = function() {
            // 随机生成 deferred对象 的状态
            var result = Math.random() > 0.5;
            if (result) {
                console.log("done() will be run...");
                // 表示成功
                dfd.resolve();
            } else {
                console.log("fail() will be run...");
                // 表示失败
                dfd.reject();
            }
        };
        setTimeout(run, 1000);
        // 返回 deferred 对象
        return dfd.promise();
    };
    
    // 根据 resolve 和 reject 状态执行回调
    $.when(wait())
        .done(function() {
            console.log("done...");
        })
        .fail(function() {
            console.log("fail...");
        });

##3. 基于自定义事件的监听 和回调很像,有些场景下可以做到比回调更好的逻辑分离

    // 添加自定义事件 监听
    $(document).on("done", function(){
        console.log("done...");
    }).on("fail", function(){
        console.log("fail...");
    });
    // 同一事件 可以添加多个监听
    // 这种方式有利于业务逻辑的分离和解耦
    $(document).on("done", function(){
        console.log("done2...");
    });
    
    setTimeout(function(){
        // 通过trigger触发该事件执行
        $(document).trigger(Math.random() > 0.5 ? "done" : "fail");
    }, 1000);

##4. 基于编译器和eval 比如 Wind.js(原名Jscex),由于作者已经停止更新,故在次不多做介绍,有兴趣的可以看这里

##5. 高阶函数篡改回调函数 参考 asyncstep

##6. 值得期待的ECMAScript6和Generator

Generator介绍

Generator的中文翻译是生成器,它是ECMAScript6(代号harmory)中提供的新特性。在过去,封装一段运算逻辑的单元是函数。函数只存在“没有被调用”或者“被调用”的情况,不存在一个函数被执行之后还能暂停的情况,而Generator的出现让这种情况成为可能。

Node.js v0.11 以上版本支持,在命令行通过参数 --harmony-generators 启动

node --harmony-generators main.js

Generator 的定义

Generator 的定义十分简单,与普通的函数相比,它只多出一个*号。以下为简单例子:

    // 采用匿名函数定义
    // 也可以才用 function* compute(a, b){} 的方式定义
    var compute = function* (a, b) {
        var sum = a + b;
        console.log(sum);
        var minus = a - b;
        console.log(minus);
        var mult = a * b;
        console.log(mult);
        var div = a / b;
        console.log(div);
    };
    
    var generator = compute(4, 2);
    // 调用next执行
    generator.next();
    
    // 输出    
    6
    2
    8
    2

yield 关键字

    // 加入 yield 关键字
    // 代码遇到 yield 将停止执行
    // 调用 next 继续运行
    var compute = function* (a, b) {
        var sum = a + b;
        yield sum;
        var minus = a - b;
        yield minus;
        var mult = a * b;
        yield mult;
        var div = a / b;
        yield div;
    };
    
    var generator = compute(4, 2);
    // 调用next执行
    // done 表示已执行完
    // done 表示是否执行完
    console.log(generator.next()); // { value: 6, done: false }
    console.log(generator.next()); // { value: 2, done: false }
    console.log(generator.next()); // { value: 8, done: false }
    console.log(generator.next()); // { value: 2, done: false }
    console.log(generator.next()); // { value: undefined, done: true }

也可以通过next传递参数

    var compute = function* (a, b) {
        var foo = yield a + b;
        console.log(foo); // 输出 Hello world!  而不是 6
    };

    var generator = compute(4, 2);
    console.log(generator.next()); // { value: 6, done: false }
    console.log(generator.next("Hello world!")); // { value: undefined, done: true }

妈妈再也不用担心 JavaScript 没有 sleep 了,使用 Co ,可以用同步的方式写异步代码,世界又美好了。

@sivagao
Copy link

sivagao commented Oct 25, 2016

good~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment