如何在 node.js 中解决可变数量的承诺
Posted
技术标签:
【中文标题】如何在 node.js 中解决可变数量的承诺【英文标题】:How to resolve a variable number of promises in node.js 【发布时间】:2015-07-01 01:02:54 【问题描述】:我正在开发一个函数(由 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(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;
【问题讨论】:
【参考方案1】:你的主要问题在这里:
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
之外。
【讨论】:
谢谢!作为一个有承诺的初学者,这非常有帮助,资源也是如此:)以上是关于如何在 node.js 中解决可变数量的承诺的主要内容,如果未能解决你的问题,请参考以下文章
Node.js / Javascript 多重递归承诺在视图中返回