涉及循环调用的异步编程技巧

537 查看

先看问题

login_label: login(user, pass, function(result) {
    doSomeThing_label: doSomeThing(result, function(err) {
        switch(err) {
        case 'disconnect':  // 第二次失败,重新登录
            goto login_label;  // 这只表示算法,并不能执行
        case 'retry':  // 第一次执行失败,重试
            goto doSomeThing_label;  // 这只表示算法,并不能执行
        default:
            logout(function() {
                console.log('finish');
            }
        }
    }
}

使用Steps解决实例(可以运行的。例子中有没有异步过程都不是问题,不信的可以自己改改验证)

var Steps = require("promise-tiny/Steps");

new Steps({
    user: 'foo',
    pass: 'foolish',
    loginCount: 0,
    doSomeThingCount: 0
}) .on('Begin', function(next) {    // 从这里开始
        next('login', [this.user, this.pass]);
    })
   .on('login', function(next, user, pass) {
        console.log('login("'+user+'", "'+pass+'")');

        this.loginCount++;

        var result = true;    // 假设login总能成功
        console.log('    第'+this.loginCount+'次login成功');
        console.log();
        next('doSomeThing', '一些要做的事情...');
    })
   .on('doSomeThing', function(next, ...args) {
        console.log('doSomeThing("'+args+'")');

        this.doSomeThingCount++;

        if(this.doSomeThingCount === 1) {    // 假设第一次做不成功,重试一次
            console.log('    第'+this.doSomeThingCount+'次doSomeThing失败,再试一次');
            next('doSomeThing', args);
        }
        else if(this.loginCount === 1) {    // 假设第二次做不成功,重新login
            console.log('    第'+this.doSomeThingCount+'次doSomeThing失败,重新login');
            next('login', [this.user, this.pass]);
        }
        else {
            console.log('    第'+this.doSomeThingCount+'次doSomeThing完成了,要退出了');
            next('logout');
        }
        console.log();
    })
   .on('logout', function(next) {
        console.log('logout()');
    })

运行结果

login("foo", "foolish")
    第1次login成功

doSomeThing("一些要做的事情...")
    第1次doSomeThing失败,再试一次

doSomeThing("一些要做的事情...")
    第2次doSomeThing失败,重新login

login("foo", "foolish")
    第2次login成功

doSomeThing("一些要做的事情...")
    第3次doSomeThing完成了,要退出了

logout()