如何在node.js

时间:2015-04-23 03:56:56

标签: javascript node.js asynchronous promise q

我正在处理一个函数(由express.js路由调用),将数据库中的事件信息与其Facebook对应项合并,并将其作为事件对象数组返回。

我遇到了node.js的异步性问题,并在返回整个对象之前解析了foreach循环中的可变数量的promise。我已经尝试了许多不同的方法来重新安排我的代码(回调,计数器,承诺等),但我没有成功解决这个问题,我真的想知道为什么。我怀疑它与foreach循环中被覆盖的变量有关,但我不确定如何解决。

我正在寻找三件事:

  1. 解决这个问题需要从概念上理解什么?
  2. 我将来如何解决这个问题或将其调试?
  3. 如何修复代码以使其正常工作?
  4. 这是我的功能:

    function mergeEvents(req, res, next, events){
    
    console.log("Merge Events");
    
    var dfd = q.defer();
    
    ensureAuthenticated(req, res, next).then(function(auth){
        var iEvent, event;
        var promises = [];
    
        if (auth){
            console.log("authenticated!");
            console.log("auth token: " + ACCESS_TOKEN);
    
            for (iEvent in events){
                event = events[iEvent];
    
                var promise = q.defer();
                promises.push(promise);
    
                https.get('https://graph.facebook.com/' + event.fb_id + '?access_token=' + ACCESS_TOKEN, function(response) {
                    var str = '';
                    response.on('data', function(chunk){
                        str += chunk;
                    });
    
                    response.on('end', function(){
                        var fb_event = JSON.parse(str);
                        event.dataValues.fb = fb_event;
                        promise.resolve(event);
                    });
                });
    
                if (promises.length == events.length){
                    console.log("last run through");
                    q.all(promises).then(function(results){
                        console.log("all promises completed?");
                        console.log(results[0]); //OUTPUT BELOW
                        //more code in here... but promises haven't resolved
                        //...
                        dfd.resolve(events);
                    });
                }
            }
        }else{
            console.log("Not authenticated. Redirecting to main page.");
            dfd.resolve(events);
        }
    });
    
    return dfd.promise;
    
    }
    

    当我尝试获取JSON对象时,它会在console.log上返回一个未解析的promise(results [0]):

    { promise: [object Object],
      resolve: [Function],
      fulfill: [Function],
      reject: [Function],
      notify: [Function] }
    

    我查看的代码参考:

    哦,这是我的单一事件fb / db合并功能的功能,所以你可以比较:

    function mergeEvent(req, res, next, event){
    console.log("Merge Event");
    
    var dfd = q.defer();
    
    ensureAuthenticated(req, res, next).then(function(auth){
        if (auth){
            console.log("authenticated!");
            console.log("auth token: " + ACCESS_TOKEN);
            https.get('https://graph.facebook.com/' + event.fb_id + '?access_token=' + ACCESS_TOKEN, function(response) {
                var str = '';
                response.on('data', function(chunk){
                    str += chunk;
                });
    
                response.on('end', function(){
                    var fb_event = JSON.parse(str);
                    event.dataValues.fb = fb_event;
                    dfd.resolve(event);
                });
            });
        }else{
            console.log("not authenticated. redirecting to main page");
            dfd.resolve(event);
        }
    });
    
    return dfd.promise;
    }
    

1 个答案:

答案 0 :(得分:6)

你的主要问题在于:

var promise = q.defer();
promises.push(promise);

q.defer()不会返回承诺。它返回deferred

var result = q.defer();
promises.push(result.promise);

正确命名变量非常重要,因为您选择了不正确的变量名称,所以没有看到错误。

有人说......

  • 避免使用for .. in。数组有.forEach().map()
  • 不是检查if (promises.length == events.length),而是将该部分移出循环。
  • 你的功能很长,可以使用一些重构。
  • 当然,不要将您的延迟对象称为“延期”或您的承诺对象“承诺”。这不是描述性的。
  • 通读What is the explicit promise construction antipattern and how do I avoid it?(让它沉入,需要一些时间)

这就是我要用的。

var q = require('q');
var qHttp = require("q-io/http"); // -> https://github.com/kriskowal/q-io

var FB = {
    // collect other FB API methods here, maybe transform into module
    graph: function (id) {
        var url = 'https://graph.facebook.com/' + id + '?access_token=' + ACCESS_TOKEN;
        return qHttp.read(url).then(function (data) {
            return JSON.parse(data.toString());
        });
    }
};

function mergeEvents(req, res, next, events) {
    return ensureAuthenticated(req, res, next).then(function (auth) {
        if (!auth) return q.reject("Not authenticated.");

        return q.all(events.map(function (event) {
            return FB.graph(event.fb_id).then(function (data) {
                event.dataValues.fb = data;
                return event;
            });
        }).then(function (results) {
            //more code in here...
        }));
    });
}

注意:如果您编写了ensureAuthenticated,请将其修改为直接拒绝,而不是使用每次使用时需要检查的虚假auth值进行解析。之后可以删除行if (!auth) ...

此外,处理“增强”事件的//more code in here...部分可能生活在mergeEvents之外。