【问题标题】:Node.JS - How to escape multiple nested callbacks?Node.JS - 如何转义多个嵌套回调?
【发布时间】:2018-09-16 10:24:37
【问题描述】:

我目前有一个 expressJS 应用程序,我正在尝试使用 getStats 函数从 API 检索信息。但是,我写的profile 路由似乎是多个嵌套回调。我将如何防止这种情况?有没有办法让它获取所有统计信息,然后在检索到所有统计信息后将它们分配给变量?

function getStats(access_token, time_range, x, callback) {
    var stats = [];

    var options = {
        url: 'www.example.com',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        json: true
    }

    request(options, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            for (i = 0; i < body.items.length; i++) {
                stats.push(body.items[i].name);
            }
            return callback(stats);
        }
    })

}

app.get('/profile', function(req, res) {
    var access_token = 1234;

    getStats(access_token, 's', 'x', function(a){
        console.log(a);

        getStats(access_token, 's', 'y', function(b){
            console.log(b);

            getStats(access_token, 'm', 'x', function(c){
                console.log(c);

                getStats(access_token, 'm', 'y', function(d){
                    console.log(d);

                    getStats(access_token, 'l', 'x', function(e){
                        console.log(e);

                        getStats(access_token, 'l', 'y', function(f){
                            console.log(f);

                            res.send(a + "\n" + b + "\n" + c + "\n" + d + "\n" + e + "\n" + f);
                        });
                    });
                });
            });
        });
    });
});

【问题讨论】:

标签: javascript node.js callback request


【解决方案1】:

Promises 允许您避免刚才展示的回调嵌套类型。请参阅我的示例,它以 Promise 形式说明了您的示例:

function getStats(access_token, time_range, x, prevResult) {
    return new Promise((resolve, reject) => {
        if (prevResult) {
            resolve([...prevResult, "test", "test", "test"]);
        } 
        return resolve(["test", "test", "test"]);

    });
}

app.get('/profile', (req, res) => {
    var access_token = 1234;

    getStats(access_token, 's', 'x')
        .then((a) => {
            console.log(a);
            return getStats(access_token, 's', 'y', a);
        })
        .then((b) => {
            console.log(b);
            return getStats(access_token, 'm', 'x', b);
        })
        .then((c) => {
            console.log(c);
            return getStats(access_token, 'm', 'y', c);
        })
        .then((d) => {
            console.log(d);
            return getStats(access_token, 'l', 'x', d);
        })
        .then((e) => {
            console.log(e);
            return getStats(access_token, 'l', 'y', e);
        })
        .then((f) => {
            console.log(f);
            res.send(f.join("\n"));
    });
});

您可以看到嵌套的回调结构并替换为更易读的格式。阅读更多关于 Promise 的信息here

上面甚至可以用Promise.all重写,看起来更好:

function getStats(access_token, time_range, x) {
    return new Promise((resolve, reject) => {
        return resolve(["test", "test", "test"]);
    });
}

app.get('/profile', (req, res) => {
    var access_token = 1234;

    Promise.all([
        getStats(access_token, 's', 'x'),
        getStats(access_token, 's', 'y'),
        getStats(access_token, 'm', 'x'),
        getStats(access_token, 'm', 'y'),
        getStats(access_token, 'l', 'x'),
        getStats(access_token, 'l', 'y')
    ]).then((values) => {
        console.log(values);
        res.send(values.join("\n"));
    });
});

【讨论】:

  • 为什么示例使用抽象getStats?问题非常具体。顺便说一句,有request-promise
  • 我提供了手头问题的最简单形式,我可以用它来说明如何改进他的代码结构。复制粘贴它并添加一些 console.log 行以查看它是如何工作的非常容易。由于原始帖子没有 API 调用,我可以很容易地重现(甚至是一个有效的),我冒昧地简化了代码以说明我的观点。 request-promise 看起来也不错,所以我想这可能是一个额外的选项来美化代码。感谢分享。
【解决方案2】:

Promise 将对此有所帮助,或者将您的回调移动到路由之外的自己的函数表达式中,然后在路由中调用一次会有所帮助。

【讨论】:

    【解决方案3】:

    回调地狱的问题在于,您没有使用 express 应用支持它的中间件。

    基本上,编写快速应用程序的一种方法是依赖回调等。但对应的是,这将导致你指出的回调地狱。

    promise 也会发生这种情况,如果处理不当,它被称为 promise hell。

    避免这两种模式的最佳方法是转向中间件解决方案。

    function getAccesstoken(req, res, next) {
        if (!req.something) {
            return next('Error, something was not specified');
        }
        req.someRequestVariable = 'set_something';
        next();
    }
    
    function processRequest(req, res, next) {
        console.log(req.someRequestVariable);
        res.send(200);
    }
    
    app.use(function genericHandlerForEveryCall() {
        console.log('This is being called in every request');
    })
    
    app.get('/profile', getAccesstoken, processRequest);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 2018-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多