我正在处理一个函数(由express.js路由调用),将数据库中的事件信息与其Facebook对应项合并,并将其作为事件对象数组返回。
我遇到了node.js的异步性问题,并在返回整个对象之前解析了foreach循环中的可变数量的promise。我已经尝试了许多不同的方法来重新安排我的代码(回调,计数器,承诺等),但我没有成功解决这个问题,我真的想知道为什么。我怀疑它与foreach循环中被覆盖的变量有关,但我不确定如何解决。
我正在寻找三件事:
这是我的功能:
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;
}
答案 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)
,而是将该部分移出循环。这就是我要用的。
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
之外。