当我尝试从map
函数的回调中返回时,我正遇到问题。与异步代码的情况一样,map函数在异步调用完成之前完成,这意味着我丢失了数据。
我可以在map
函数中做些什么来确保异步调用完成?我试图只从一个promise返回,但似乎map函数在到达结尾时返回null。
在我的具体示例中,我尝试从Yelp API中获取大量业务,然后对其各自的地址进行地理编码,以便将其添加到我网站上的Google地图中。
代码:
Q.Promise(function(resolve, reject, notify) {
yelp.search({
category_filter: 'food,restaurants',
location: city,
limit: 3,
sort: 2, // sort mode: 2=Highest Rated
}, function(error, data) {
if (error) {
reject(new Error(error));
}
else {
if (data['businesses'] && data['businesses'].length > 0) {
results = data['businesses'].map(function(business) {
sleep.usleep(500000); // sleep for 0.5 seconds so as not to get throttled by google
address = business.location.display_address.join(', ');
geocoder.geocode(address)
.then(function(res) {
return {
img_url: business.image_url,
name: business.name,
url: business.url,
rating_img_url: business.rating_img_url,
address: address,
coords: [res[0]['latitude'], res[0]['longitude']],
}
})
.catch(function(err) {
console.log('Could not geocode: ' + err);
return;
});
});
resolve(results);
}
}
});
});
答案 0 :(得分:0)
我讨厌提出一种不那么“功能性”的方法(see wikipedia,特别是关于副作用的部分),但是如果你愿意使用一个改变对象属性的简单循环,那么应该这样做:< / p>
data.forEach(function(business) {
// code removed
.then(function(res) {
business.businesses = /* the new object */
})
// code removed
在上述方法中,您只需迭代data
并改变当前迭代businesses
的相应business
属性。
我认为大多数其他方法可能有点复杂/混淆,所以这可能是“较少的邪恶”类型的东西。其他选项包括将所有承诺存储在新阵列中,并使用Q.allSettled
之类的东西将它们与相应的business
属性相匹配。但不确定这是否是一种最佳方法。
答案 1 :(得分:0)
除了Josh Beam的回答之外,我将发布一个我想到的解决方案,它实际上将地理编码代码放入一系列被调用的Promise中,然后返回Yelp承诺的结果。 :
Q.Promise(function(resolve, reject, notify) {
yelp.search({
category_filter: 'food,restaurants',
location: city,
limit: 3,
sort: 2, // sort mode: 2=Highest Rated
}, function(error, data) {
if (error) {
reject(new Error(error));
}
else {
if (data['businesses'] && data['businesses'].length > 0) {
// we only need some of the properties of a Yelp business result
geoQueries = [];
results = data['businesses'].map(function(business) {
geoQueries.push(Q.Promise(function(resolve, reject, notify) {
// sleep for 0.5 seconds so as not to get throttled by google
sleep.usleep(500000);
address = business.location.display_address.join(', ');
geocoder.geocode(address)
.then(function(res) {
resolve({
img_url: business.image_url,
name: business.name,
url: business.url,
rating_img_url: business.rating_img_url,
address: address,
coords: [res[0]['latitude'], res[0]['longitude']],
});
})
.catch(function(err) {
console.log('Could not geocode: ' + err);
return;
});
}));
});
Q.all(geoQueries)
.then(function(data) {
resolve(data);
});
}
}
});
});