如何处理Node.js模块中的异步回调?

时间:2014-08-11 22:13:55

标签: javascript node.js callback promise

这是我尝试将节点模块组合在一起的第一次尝试,我仍然试图围绕如何构建异步回调。这就是一个例子。现在我正在尝试使用featureService.getCount()并且没有得到任何响应。使用断点,我知道featureService.getUniqueIds()正在运行。

由于回调就在那里,我假设我没有得到长度的原因是getCount中的回调还没有响应。在下午的大部分时间看到这个并没有真正提出一个非常好的解决方案,而不是递归循环检查要用超时填充的值,我正在寻求建议如何更好地构造我的代码来完成任务在手边。

我已经阅读了一些关于承诺的内容。这是一个适用的实例,还是一个可行的解决方案?我真的不知道如何实现promises,但在这样的实例中它具有逻辑意义。

显然我迷失在这里。感谢您提供任何帮助。

var Client = require('node-rest-client').Client;
var client = new Client();

var featureService = function(endpoint){

    var uniqueIds;
    var count;

    // get list of unique id's
    this.getUniqueIds = function(){
        if (!uniqueIds) {
            var options = {
                parameters: {
                    f: 'json',
                    where: "OBJECTID LIKE '%'",
                    returnIdsOnly: 'true'
                }
            };
            client.get(endpoint + '/query', options, function(data, res){
                var dataObject = JSON.parse(data);
                var uniqueIds = dataObject.objectIds;
                return uniqueIds;
            });
        } else {
            return uniqueIds;
        }
    };

    // get feature count
    this.getCount = function(){

        // get uniqueIds
        uniqueIds = this.getUniqueIds();

        // get length of uniqueIds
        count = uniqueIds.length;
    };

    // get list of unique attribute values in a single field for typeahead
    this.getTypeaheadJson = function(field){};

    // find features in a field with a specific value
    this.find = function(field, value){};
};

var endpoint = 'http://services.arcgis.com/SgB3dZDkkUxpEHxu/arcgis/rest/services/aw_accesses_20140712b/FeatureServer/1';
var afs = new featureService(endpoint);
console.log(afs.getCount());

exports.featureService = featureService;

现在,在使用request文档(我无法使上述模块工作)之后再使用bluebird之后,我有这个工作,但无法弄清楚如何得到要使用的计算值,迭代次数。

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

var FeatureService = function(){

    // get count from rest endpoint
    var getCount = function(){
        var optionsCount = {
            url: endpoint + '/query',
            qs: {
                f: 'json',
                where: "OBJECTID LIKE '%'",
                returnCountOnly: 'true'
            }
        };
        return request.getAsync(optionsCount)
            .get(1)
            .then(JSON.parse)
            .get('count');
    };

    // get max record count for each call to rest endpoint
    var getMaxRecordCount = function(){
        var optionsCount = {
            url: endpoint,
            qs: {
                f: 'json'
            }
        };
        return request.getAsync(optionsCount)
            .get(1)
            .then(JSON.parse)
            .get('maxRecordCount');
    };

    // divide the total record count by the number of records returned per query to get the number of query iterations
    this.getQueryIterations = function(){
        getCount().then(function(count){
            getMaxRecordCount().then(function(maxCount){
                return  Math.ceil(count/maxCount);
            });
        });
    };

};

// url to test against
var endpoint = 'http://services.arcgis.com/SgB3dZDkkUxpEHxu/arcgis/rest/services/aw_accesses_20140712b/FeatureServer/1';

// create new feature service object instance
afs = new FeatureService();

// This seems like it should work, but only returns undefined
console.log(afs.getQueryIterations());

// this throws an error telling me "TypeError: Cannot call method 'then' of undefined"
//afs.getQueryIterations().then(function(iterCount){
//    console.log(iterCount);
//});

1 个答案:

答案 0 :(得分:2)

是的,使用承诺!他们是powerful tool,正是为了这个目的而制作的,并且decent library他们很容易使用。在你的情况下:

var Promise = require('bluebird'); // for example, the Bluebird libary
var Client = Promise.promisifyAll(require('node-rest-client').Client);
var client = new Client();

function FeatureService(endpoint) {

    var uniqueIds;
    var count;

    // get list of unique id's
    this.getUniqueIds = function(){
        if (!uniqueIds) { // by caching the promise itself, you won't do multiple requests
                          // even if the method is called again before the first returns
            uniqueIds = client.getAsync(endpoint + '/query', {
                parameters: {
                    f: 'json',
                    where: "OBJECTID LIKE '%'",
                    returnIdsOnly: 'true'
                }
            })
            .then(JSON.parse)
            .get("objectIds");
        }
        return uniqueIds;
    };

    // get feature count
    this.getCount = function(){
        if (!count)
            count = this.getUniqueIds() // returns a promise now!
                    .get("length");
        return count; // return a promise for the length
    };

    // get list of unique attribute values in a single field for typeahead
    this.getTypeaheadJson = function(field){};

    // find features in a field with a specific value
    this.find = function(field, value){};
};

var endpoint = 'http://services.arcgis.com/SgB3dZDkkUxpEHxu/arcgis/rest/services/aw_accesses_20140712b/FeatureServer/1';
var afs = new FeatureService(endpoint);
afs.getCount().then(function(count) {
    console.log(count);
}); // you will need to use a callback to do something with async results (always!)

exports.FeatureService = FeatureService;

此处,使用Bluebird's Promise.promisifyAll,您只需使用.getAsync()代替.get(),即可获得结果承诺。


// divide the total record count by the number of records returned per query to get the number of query iterations
this.getQueryIterations = function(){
    getCount().then(function(count){
        getMaxRecordCount().then(function(maxCount){
            return  Math.ceil(count/maxCount);
        });
    });
};

这是正确的想法!只有总是希望return来自.then处理程序的内容,以便.then()调用返回的承诺将使用该值解析。

// divide the total record count by the number of records returned per query to get the number of query iterations
this.getQueryIterations = function(){
    return getCount().then(function(count){
//  ^^^^^^ return the promise from the `getQueryIterations` method
        return getMaxRecordCount().then(function(maxCount){
//      ^^^^^^ return the promise for the iteration number
            return  Math.ceil(count/maxCount);
        });
    });
};

现在,您返回promise for the innermost result,现在可以使用了:

afs.getQueryIterations().then(function(iterCount){
    console.log(iterCount);
});