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

Expressjs, async and middleware does not work properly

我正在使用 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 ) );
});

控制台输出如下(运行s before that middleware returns the value):

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

但我认为是扩展代码,重复调用和检查。我知道,因为它不适用于上面返回值的代码。我认为使用异步瀑布 运行 宁代码系列并且直到最后才返回它,阻塞代码。

不应该是同步和阻塞代码的延续吗?

谢谢。

正如您所指出的,问题是 getData returns 立即。 async 不是 'escape async',它是一组以异步方式 围绕控制流的模式 。结果仍然是异步的。另外,不要使用 "deasync" 库。

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

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

你这里有一个基本的控制流问题。您的 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);
    });
});

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