Expressjs,异步和中间件无法正常工作

时间:2015-12-09 17:04:17

标签: node.js asynchronous express async.js

我正在使用框架expressjs进行测试,我在其中创建一个在路由块之前运行的中间件,但它无法正常工作。

我认为可能是我的代码逃脱了异步并且它无法正常运行,但我对代码进行了一些更改,故障仍然让我失望。对于我做的更多测试和尝试,我找不到错误。

我的代码如下:

function getData(hostname, number, string, cb) {

    async.waterfall([

        function(callback) {

            console.log('1');
            callback(null, null);
        },
        function(first, callback) {

            console.log('2');
            callback(null, null);
        },
        function(second, callback) {

            console.log('3');
            callback(null, []);
        }
    ],
    function(err, results) {

        if( typeof cb === 'function') {

            return cb(null, results);
        }

        return results;
    });
}

// Request middleware
app.use(function(req, res, next) {

    res.locals['data'] = getData(req.hostname, 40, 'demo');

    next();
});

app.get('/demo', function(req, res) {

    res.send('Demo');

    console.log( JSON.stringify( res.locals ) );
});

控制台上的输出如下(在该中间件返回值之前运行):

debug: 1
{}
GET /demo 200 10.654 ms - 9
debug: 2
debug: 3
GET /favicon.ico - - ms - -

只有在以下列方式修改代码时才能正确使用我:

// Request middleware
app.use(function(req, res, next) {

    if( req.method === 'GET' ) { // Only get request

        getData(req.hostname, 40, 'demo', function(err, data) {

            req.locals['data'] = data;

            next();
        });

    } else {

        next();
    }
});

但我认为这是扩展代码,重复调用和检查。我知道,因为它不能与返回值的上述代码一起使用。我认为使用异步瀑布运行代码系列并且直到最后都不返回,阻止代码。

不应该同步并阻止代码的继续吗?

谢谢。

2 个答案:

答案 0 :(得分:2)

正如您所指出的,问题是getData立即返回。 async没有“逃避异步”,它是一组以异步方式围绕控制流的模式。结果仍然是异步的。另外,请勿使用“deasync”库。

您可能对使用生成器的koa感兴趣(需要ES6 - 即节点v4或带有--harmony的节点0.12),以便让您编写较少“回调”驱动的代码。例如这将是koa中间件:

app.use(function*(next) {
  res.locals['data'] = yield getData(req.hostname, 40, 'demo');
  yield* next;
});

答案 1 :(得分:-1)

这里有一个基本的控制流问题。您的getData函数同时尝试同步和异步,同时使用纯异步控制流。

async.waterfall方法用于一个接一个地执行一系列异步方法,将结果从一个方法传递到链中的下一个方法。如果任何方法回调错误,瀑布将被中断。

根据这些信息,您应该重构getData()方法:

function getData(hostname, number, string, cb) {
    async.waterfall([
        function(callback) {
            console.log('1');
            callback();
        },
        function(first, callback) {
            console.log('2');
            callback();
        },
        function(second, callback) {
            console.log('3');
            callback(null, []);
        }
    ],
    function(err, results) {
        return cb(err, results);
    });
}

现在,在将此方法连接到中间件时,您可以将next函数作为回调值传递:

app.use(function(req, res, next) {
    getData(req.hostname, 40, 'demo', function(err, results) {
        res.locals.data = results;
        next(err);
    });
});

我希望这是有道理的。基本上你只是在这里混合和匹配同步和异步概念。