【问题标题】:Javascript Callback Inside Map地图内部的 Javascript 回调
【发布时间】:2015-08-19 04:15:21
【问题描述】:

当我尝试从 map 函数中的回调返回时,我目前遇到了问题。与异步代码的通常情况一样,map 函数在异步调用完成之前完成,这意味着我丢失了数据。

我可以在map 函数中做些什么来确保异步调用完成?我试图只从承诺中返回,但似乎 map 函数在到达末尾时返回 null。

在我的具体示例中,我尝试从 Yelp API 获取一堆企业,然后对它们的各个地址进行地理编码,以便我可以将它们添加到我网站上的 Google Maps 地图中。

代码:

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);
      }
    }
  });
});

【问题讨论】:

    标签: javascript node.js google-maps asynchronous


    【解决方案1】:

    我讨厌建议一种不太“功能性”的方法(see wikipedia,尤其是关于副作用的部分),但如果您愿意使用一个简单的循环来改变对象属性,它应该可以解决问题:

    data.forEach(function(business) {
              // code removed
                .then(function(res) {
                  business.businesses = /* the new object */
                })
                // code removed
    

    在上述方法中,您只需迭代 data 并改变当前迭代的 business 的适当 businesses 属性。

    我认为大多数其他方法可能有点令人费解/混淆,所以这可能是一种“恶少”类型的事情。其他选项包括将所有 Promise 存储在一个新数组中,并使用 Q.allSettled 之类的东西将它们与适当的 business 属性匹配。不过,不确定这是否是最佳方法。

    【讨论】:

    • 我目前正在考虑在 Promise 中执行 Promise(所以我将执行 Q.all(geoQueries))。您如何看待这个解决方案相对于您的解决方案的优点?另外,为什么 forEach 不会像 map 一样在异步回调上失败?
    • @tsurantino,我尽量避免使用整个 promises-within-promises 方法,因为它通常最终会变得非常不可读。我认为forEach 不会“失败”,因为then 内部的回调只是存储对当前迭代的business 的引用,当承诺解决时,它会调用适当的回调并映射到适当的对象.我可能是错的,但在我们现在正在进行的项目中,这种模式或多或少地被“成功”地使用了。
    • 有道理!我现在正在忙,所以我将在 Promises 方法中发布 Promises 作为另一个可选答案。我回家后会试试你的方法。如果它有效并且更具可读性,我将奖励您的答案:) 再次感谢您抽出宝贵时间回复。
    • @tsurantino,肯定没有问题!希望您能找到合适的解决方案。
    【解决方案2】:

    除了 Josh Beam 的回答之外,我将发布一个我想到的解决方案,它实际上将地理编码代码放入一个单独的一系列被调用的承诺中,然后返回 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);
            });
          }
        }
      });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-08
      • 2023-04-07
      • 1970-01-01
      • 2011-12-18
      • 2018-09-04
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多