多层闭包和同步javascript
这是我上一篇文章的延伸,它得到了一个非常解释性的答案。事实证明,我没有为我的应用程序提供足够的上下文,使这个问题对我的实际情况足够有用 以下是我的Express应用程序中的路线:多层闭包和同步javascript,javascript,node.js,closures,synchronous,Javascript,Node.js,Closures,Synchronous,这是我上一篇文章的延伸,它得到了一个非常解释性的答案。事实证明,我没有为我的应用程序提供足够的上下文,使这个问题对我的实际情况足够有用 以下是我的Express应用程序中的路线: var eventbriteService = require('../apiRequests/eventbriteService'); var queue = require('queue-async'); app.get('/events', function (req, res, next) {
var eventbriteService = require('../apiRequests/eventbriteService');
var queue = require('queue-async');
app.get('/events', function (req, res, next) {
queue()
.defer(eventbriteService.getEventbriteEvents)
.await(function(err, data) {
if (err) {return next(err);}
console.log("here are the events from routes" ,data);
});
});
此路由调用以下服务:
exports.getEventbriteEvents = function (cb) {
var eventbriteEvents = [];
request({
uri: "https://www.eventbrite.com/json/event_search?app_key=R3DQQXPXBTSMUWVNOV&city=Austin&date=2014-10-01&2014-10-15",
method: "GET", timeout: 10000, followRedirect: true, maxRedirects: 10,
}, function(err, response, body){
if (err) return cb(err);
try {
var eventsJSON = JSON.parse(body);
var eventsWithAllFields = eventsJSON.events;
var totalEventsNumber = parseInt(eventsWithAllFields[0].summary.total_items);
for (var i = 1, l = eventsWithAllFields.length; i < l; i++) {
var eventObject = {
name: eventsWithAllFields[i].event.title,
images: []
};
var jsdom = require('jsdom');
var arrayOfImgs = [];
jsdom.env({
html: eventsWithAllFields[i].event.description,
scripts: ["http://code.jquery.com/jquery.js"],
done: function(evtobj, errors, window) {
window.$('img').each(function(){
var imgSrc = window.$(this).attr('src');
console.log(imgSrc);
evtobj.images.push(imgSrc);
});
eventbriteEvents.push(evtobj);
}.bind(null, eventObject)
});
}
} catch(err) {
console.log(err);
return cb(err);
}
console.log(eventbriteEvents);
cb(null, eventbriteEvents);
});
};
代码按以下顺序执行:
我正在使用队列异步库定义路由中的回调,该回调最终由eventbrite服务填充。在我最近添加jsdom html解析功能之前,这一切都很好。除了解决这个紧迫的问题外,我还寻求帮助构建回调、闭包和同步代码的心智模型 问题在于,当
for
循环完成时,您正在调用回调,但是for
循环在其每次循环中调用异步函数(jsdom.env
)。最终发生的是for
循环在调用的函数完成之前完成循环
您需要的是在所有异步函数完成后调用回调的东西。由于您已经在其他地方使用了queue async
,所以让我们使用它(请参阅修改后的代码中的注释):
var queue=require('queue-async');
exports.getEventbriteEvents=函数(cb){
请求({
uri:“https://www.eventbrite.com/json/event_search?app_key=&city=Austin&date=2014-10-01&2014-10-15",
方法:“GET”,超时:10000,followRedirect:true,maxRedirects:10,
},功能(错误、响应、正文){
如果(错误)返回cb(错误);
试一试{
var jsdomQueue=queue();
var eventsJSON=JSON.parse(body);
var eventsWithAllFields=eventsJSON.events;
var totalEventsNumber=parseInt(eventsWithAllFields[0]。summary.total\u items);
对于(变量i=1,l=eventsWithAllFields.length;i
这不是一个真正的答案,但是签出对于处理复杂的回调层次结构非常有用。我根本没有得到任何输出。似乎执行永远不会返回routes文件中的队列异步,因为我甚至从未记录硬编码的“此处是routes的事件”。很抱歉,我在移动该时遗漏了一个需要绑定的变量(i
)。bind
调用(我已编辑了答案)。仍然没有任何内容。是什么导致它无法将控制权返回到路由?嗯,如果您的回调cb
从未被调用,那么就会发生这种情况。听起来像是在jsdomQueue中的回调。出于某种原因,waitAll
没有被调用。哦,你注意到我在request
suri
参数中更改了你的app\u键吗?(我想你可能不想让它到处都是。对不起,我应该提到这一点)
{}
[]
here are the events from routes []
https://evbdn.eventbrite.com/s3-s3/eventlogos/90039995/about.png
https://evbdn.eventbrite.com/s3-s3/eventlogos/90039995/bluedawntour1.jpg
var queue = require('queue-async');
exports.getEventbriteEvents = function (cb) {
request({
uri: "https://www.eventbrite.com/json/event_search?app_key=<redacted>&city=Austin&date=2014-10-01&2014-10-15",
method: "GET", timeout: 10000, followRedirect: true, maxRedirects: 10,
}, function(err, response, body){
if (err) return cb(err);
try {
var jsdomQueue = queue();
var eventsJSON = JSON.parse(body);
var eventsWithAllFields = eventsJSON.events;
var totalEventsNumber = parseInt(eventsWithAllFields[0].summary.total_items);
for (var i = 1, l = eventsWithAllFields.length; i < l; i++) {
var eventObject = {
name: eventsWithAllFields[i].event.title,
images: []
};
var jsdom = require('jsdom');
// push ("defer") the jsdom.env async function on to the jsdomQueue
// note: we have to move the .bind for that to still work
jsdomQueue.defer(function(i, evtobj, deferCallback) {
jsdom.env({
html: eventsWithAllFields[i].event.description,
scripts: ["http://code.jquery.com/jquery.js"],
done: function(errors, window) {
window.$('img').each(function(){
var imgSrc = window.$(this).attr('src');
console.log(imgSrc);
evtobj.images.push(imgSrc);
});
// call the deferCallback with the evtobj
deferCallback(null, evtobj);
}
});
}.bind(null, i, eventObject));
}
// wait for all the previously deferred functions to finish.
// the objects passed to deferCallback above will be in the
// eventbriteEvents array.
jsdomQueue.awaitAll(function(err, eventbriteEvents) {
if (err) {
// any additional error handling
cb(err);
} else {
// now you can call your callback
console.log(eventbriteEvents);
cb(null, eventbriteEvents);
}
});
} catch(err) {
console.log(err);
return cb(err);
}
});
};