4

假设我想发送一封电子邮件然后更新数据库,这两个操作都是异步的。这就是我通常会写它的方式。

send_email(function(err, id){
    if(err){
        console.log("error");
    }else{
        update_database(id,function(err, id){
            if(err){
                console.log("error");
            }else{
                console.log("success");
            }
        });
    }
});

我想用中间件来代替。

var mid = {};

mid.send_email = function(){
    return function(next){
        send_email(function(err,id){
            if(err){
                console.log("error");
            }else{
                next(id);
            }
        });
    }
}

mid.update_database = function(){
    return function(id,next){
        update_database(id,function(err,id){
            if(err){
                console.log("error");
            }else{
                next(id);
            }
        });
    }
}

mid.success = function(){
    return function(id,next){
        console.log("success")
        next(id);
    }   
}

堆叠中间件。

middleware.use(mid.send_email());
middleware.use(mid.update_database());
middleware.use(mid.success());

手头有两个主要问题。

  • 如何使用中间件代替嵌套回调?
  • 是否可以将变量传递给next()?
4

3 回答 3

5

您想要的是能够处理异步控制流。很多 js 库可以帮助你实现这一点。您可以尝试Async使用该函数的库,waterfall因为您希望能够将变量传递给将要执行的下一个函数:

https://github.com/caolan/async#waterfall

“连续运行一系列函数,每个函数将其结果传递给数组中的下一个。但是,如果任何函数将错误传递给回调,则不会执行下一个函数,并且会立即调用主回调并显示错误。”

例子 :

async.waterfall([
    function(callback){
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback){
        callback(null, 'three');
    },
    function(arg1, callback){
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'    
});
于 2013-01-04T02:11:38.390 回答
1

使用CommonJSmodule.exports可能会更好。

你可以像这样创建一个文件:

module.exports = function (){
    function sendEmail(doneCallback){
        // do your stuff, then when you are done:
        if(!err){
            doneCallback(whatever,args,you,need);
        }
    }

    function updateDB(success){
        // do your stuff, then when you are done:
        success(whatever,args,you,need);
    }

    return {
        send: sendEmail,
        update: updateDB
    };
};

然后在你的server.js

var lib = require('./mylib.js');

lib.send(function(result){
   console.log(result);
});

这是一个类似的模式,它可能会让你更好地理解我的意思。它由库烘焙 afunction并将其传递给需要链接的任何人组成,如下所示(更实际的示例,这次是客户端):

ui.bistate($('#mybutton'), function(restore){
    $.ajax({
        url: '/api/1.0/catfood',
        type: 'PUT',
        data: {
            catfood: {
                price: 1.23,
                name: 'cheap',
                text: 'Catzy'
            }
        }
    }).done(function(res){
        // stuff with res
        restore();
    });
});

在图书馆中,这restore就是提供的方式:

var ui = function(){
    function bistate(button, action) {
        var originalText = buttonText.data('text'),
            disabledText = buttonText.data('text-disabled');

        function restore(){
            button.prop('disabled', false);
            button.text(originalText);
        }

        function disable(){
            button.prop('disabled', true);
            button.text(disabledText);
        }

        button.on('click', function(){
            disable();
            action(restore);
        });
        restore();
    }

    return {
        bistate: bistate
    };
}();

允许消费者在想要恢复按钮时控制流程,并让库不必处理消费者想要在两者之间进行异步操作的复杂情况。

总的来说,要点是:来回传递回调是巨大的,并且使用得不够广泛

于 2013-01-04T02:36:43.043 回答
0

一段时间以来,我一直在工作中使用Queue.js 。

于 2013-01-20T03:51:32.243 回答