我可以用啥来替换嵌套的异步回调?

Posted

技术标签:

【中文标题】我可以用啥来替换嵌套的异步回调?【英文标题】:What can I use to replace nested async callbacks?我可以用什么来替换嵌套的异步回调? 【发布时间】:2012-12-18 11:10:25 【问题描述】:

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

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()

【问题讨论】:

这叫“排队” 尚不清楚您帖子中的“中间件”是指某个特定的库还是“有助于...的库”。标签“中间件”肯定没有特定于 javascript 的内容。 @AlexeiLevenkov 我明白你的意思。我使用了middleware 这个词,因为这就是技术。但我也不确定是否有图书馆。 @zzzzBov 我对“排队”进行了一些搜索,但找不到任何我想要的东西。你有参考吗? 听起来像github.com/caolan/async#series 【参考方案1】:

我在工作中一直使用Queue.js。

【讨论】:

【参考方案2】:

您最好使用CommonJS module.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);
);

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

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
    ;
();

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

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

【讨论】:

【参考方案3】:

您想要的是能够处理异步控制流。很多 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'    
);

【讨论】:

以上是关于我可以用啥来替换嵌套的异步回调?的主要内容,如果未能解决你的问题,请参考以下文章

异步 node.js:带有回调的嵌套数组

重构嵌套回调、node.js、异步

嵌套的异步回调

flutter 同时执行多个异步请求回调

javascript中异步操作的异常怎么处理

JS的Promise兄弟