如何解决 node.js 中可变数量的承诺
How to resolve a variable number of promises in node.js
我正在开发一个函数(由 express.js 路由调用)以将数据库中的事件信息与其 Facebook 对应项合并,并 return 将其作为事件对象数组。
我在处理 node.js 的异步特性时遇到问题,在 return 处理整个对象之前,我无法解决 foreach 循环中可变数量的承诺。我已经尝试了很多不同的方法来重新排列我的代码(回调、计数器、承诺等),但我没有成功解决这个问题,我真的很想知道为什么。我怀疑这与在 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 对象,但它 return 是 console.log(results[0]) 上的未解决承诺:
{ promise: [object Object],
resolve: [Function],
fulfill: [Function],
reject: [Function],
notify: [Function] }
我查看过的代码参考:
- https://github.com/kriskowal/q
- https://github.com/kriskowal/q/wiki/API-Reference
- https://strongloop.com/strongblog/how-to-compose-node-js-promises-with-q/
- http://thejsguy.com/javascript/node.js/2014/06/27/JavaScript-Flow-Control.html
哦,这是我的单个事件 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;
}
你的主要问题在这里:
var promise = q.defer();
promises.push(promise);
q.defer()
没有 return 承诺。它 return 是 deferred。
var result = q.defer();
promises.push(result.promise);
正确命名变量很重要,您没有看到错误是因为您选择了不正确的变量名。
话虽这么说...
- 避免
for .. in
。数组有 .forEach()
或 .map()
.
- 不检查
if (promises.length == events.length)
,而是将该部分移出循环。
- 您的函数很长,可以进行一些重构。
- 当然,不要调用您的延迟对象 "deferred" 或您的承诺对象 "promise"。这不是描述性的。
- 通读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) ...
。
此外,处理 "enhanced" 事件的 //more code in here...
部分应该 可能 位于 mergeEvents
之外。
我正在开发一个函数(由 express.js 路由调用)以将数据库中的事件信息与其 Facebook 对应项合并,并 return 将其作为事件对象数组。
我在处理 node.js 的异步特性时遇到问题,在 return 处理整个对象之前,我无法解决 foreach 循环中可变数量的承诺。我已经尝试了很多不同的方法来重新排列我的代码(回调、计数器、承诺等),但我没有成功解决这个问题,我真的很想知道为什么。我怀疑这与在 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 对象,但它 return 是 console.log(results[0]) 上的未解决承诺:
{ promise: [object Object],
resolve: [Function],
fulfill: [Function],
reject: [Function],
notify: [Function] }
我查看过的代码参考:
- https://github.com/kriskowal/q
- https://github.com/kriskowal/q/wiki/API-Reference
- https://strongloop.com/strongblog/how-to-compose-node-js-promises-with-q/
- http://thejsguy.com/javascript/node.js/2014/06/27/JavaScript-Flow-Control.html
哦,这是我的单个事件 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;
}
你的主要问题在这里:
var promise = q.defer();
promises.push(promise);
q.defer()
没有 return 承诺。它 return 是 deferred。
var result = q.defer();
promises.push(result.promise);
正确命名变量很重要,您没有看到错误是因为您选择了不正确的变量名。
话虽这么说...
- 避免
for .. in
。数组有.forEach()
或.map()
. - 不检查
if (promises.length == events.length)
,而是将该部分移出循环。 - 您的函数很长,可以进行一些重构。
- 当然,不要调用您的延迟对象 "deferred" 或您的承诺对象 "promise"。这不是描述性的。
- 通读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) ...
。
此外,处理 "enhanced" 事件的 //more code in here...
部分应该 可能 位于 mergeEvents
之外。