Q.all 请求承诺数组,不确定如何获得结果

Q.all array of request promises, not sure how to get the results

可能是一个明显的答案,但我不确定该采取什么方式。 请求是一个节点模块:https://github.com/request/request 我填充了一组 getHistory 请求(使用不同的参数)。 p = [p1,p2...].

this.app.all('/api/heatmap', function(req,res) {
   // fill p here _.each(blabla, p.push(gethistory(someparams...)
   var result = [];
   function getHistory(params) {
        var options = { ...};
        var callback = function(error, response, body) {
            if(error) { //wtv 
            } else {
              // what to do with the body here ? return body ? result.push(body) ?
            }
        }

        request(options, callback);
    }

    Q.all(p).then(function() {
    });
}

所以这里的问题是我在完成所有请求时,将所有内容都放在 array/object 中,然后将整个内容发送给客户端。如何让 getHistory 返回获取的值(请求完成后)。

希望清楚。

这里的核心问题是node.js-style回调和promises不兼容。 Promises 强调 return 值,node 强调回调。

因此,您需要一种适配器来正确包装节点的回调约定,为此需要一个名为 Promisifcation. This can be done manually, but it's tedious at best and error-prone when you are not careful. Luckily, since node's conventions are well-established, it can be automated. Q has a few helpers 的过程,但 Bluebird 在这方面要方便得多。

所以最简单的方法是切换到 Bluebird 作为 promise 库并使用 promisifyAll

var Promise = require('bluebird');
var request = Promise.promisifyAll(require("request"));

this.app.all('/api/heatmap', function(req, res) {
    var requests = blabla.map(function (item) {
        return request.getAsync({ /* params */ });
    });

    Promise.all(requests).then(function (responses) {
        res.send( JSON.stringify(responses) ); // whatever
    }).catch(function (error) {
        res.send( "An error ocurred: " + error ); // handle error
    });
}

使用了 Q.deferred 并按照记录工作 \o/

function getHistory(params) {
                var deferred = Q.defer();
                var options = {
                    method: 'GET',
                    url: 'https://api.kaiko.com/v1/charts/' + params.exchange + '/' + params.pair +'/history',
                    qs:qs,
                    headers: {
                        "Content-Type": "application/json",
                        "Accept": "application/json"
                    }
                }

                var callback = function(error, response, body) {
                    if(error) {
                        console.log('error fetching trades', error);
                        res.send(500, 'Something went wrong while fetching trades');
                    } else {
                        var body = heatmapVolume(body, params.exchange, params.pair);
                        // console.log("result!", body.exchange, body.pair);
                        result.push(body);
                        // return body;
                        deferred.resolve();
                    }
                }

                request(options, callback);

                return deferred.promise;
            }

FWIW,这是另一个答案,它显示了正确完成 Q 后的效果:

// promisified request
function requestAsync(options) {
    var result = Q.defer();
    request(options, function(error, response, body) {
        if (error) {
            result.reject(error);
        } else {
            result.resolve(body);
        }
    });
    return result.promise;
}

// returns promises for heatmapVolumes
function getHistory(params) {
    return requestAsync({
        method: 'GET',
        url: 'https://api.kaiko.com/v1/charts/' + 
            encodeURIComponent(params.exchange) + '/' + 
            encodeURIComponent(params.pair) +'/history',
        qs: params.qs,
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
    }).then(function (body) {
        return heatmapVolume(body, params.exchange, params.pair);
    }).catch(function (error) {
        // log detailed error and send less revealing message downstream
        console.error('error fetching trades', error);
        throw new Error('Something went wrong while fetching trades');
    });
}

// usage
this.app.all('/api/heatmap', function(req, res) {
    getHistory({
        exchange: "foo", pair: "bar", qs: "qux"
    }).then(function (heatmap) {
        res.send(200, heatmap);
    }).catch(function (error) {
        res.send(500, error);
    });
});