Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/416.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
映射内的Javascript回调_Javascript_Node.js_Google Maps_Asynchronous - Fatal编程技术网

映射内的Javascript回调

映射内的Javascript回调,javascript,node.js,google-maps,asynchronous,Javascript,Node.js,Google Maps,Asynchronous,当我试图从map函数中的回调返回时,当前遇到了一个问题。与异步代码通常的情况一样,map函数在异步调用完成之前完成,这意味着我丢失了数据 在map函数中我可以做什么来确保异步调用完成?我试图只从承诺中返回,但似乎map函数在到达末尾时返回null 在我的具体例子中,我试图从YelpAPI中获取一些企业,然后对它们的地址进行地理编码,这样我就可以将它们添加到我网站上的谷歌地图中 代码: 我不喜欢建议一种不太“实用”的方法(特别是关于副作用的部分),但是如果你愿意使用一个简单的循环来改变对象属性,它

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

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

在我的具体例子中,我试图从YelpAPI中获取一些企业,然后对它们的地址进行地理编码,这样我就可以将它们添加到我网站上的谷歌地图中

代码:

我不喜欢建议一种不太“实用”的方法(特别是关于副作用的部分),但是如果你愿意使用一个简单的循环来改变对象属性,它应该做到:

data.forEach(function(business) {
          // code removed
            .then(function(res) {
              business.businesses = /* the new object */
            })
            // code removed
在上述方法中,您只需迭代
数据
,并修改当前迭代的
业务
的相应
业务
属性

我认为大多数其他方法可能有点复杂/模糊,因此这可能是一种“较小的邪恶”类型的事情。其他选项包括将所有承诺存储在一个新数组中,并使用类似于
Q.allSettled
的内容将它们与相应的
业务
属性相匹配。不过,我不确定这是否是一种最佳方法。

我讨厌建议一种“功能性”较差的方法(尤其是关于副作用的部分),但如果您愿意使用一个简单的循环来改变对象属性,它应该做到:

data.forEach(function(business) {
          // code removed
            .then(function(res) {
              business.businesses = /* the new object */
            })
            // code removed
在上述方法中,您只需迭代
数据
,并修改当前迭代的
业务
的相应
业务
属性


我认为大多数其他方法可能有点复杂/模糊,因此这可能是一种“较小的邪恶”类型的事情。其他选项包括将所有承诺存储在一个新数组中,并使用类似于
Q.allSettled
的内容将它们与相应的
业务
属性相匹配。不过,我不确定这是否是一种最佳方法。

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

除了Josh Beam的回答之外,我还将发布一个我想到的解决方案,在返回Yelp promise的结果之前,它实际上将地理编码代码放入一系列单独的承诺中,并被调用

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

我目前正在考虑在一个承诺中做一个承诺(因此我将做Q.all(地理查询))。你认为这个解决方案比你的有什么优点?还有,为什么forEach不能像map那样在异步回调中失败呢?@tsurantino,我尽量避免使用承诺中的承诺方法,因为它通常会非常不可读。我认为
forEach
不会“失败”,因为
then
内部的回调只是存储对当前迭代的
业务的引用,当承诺解决时,它调用适当的回调并映射到适当的对象。我可能错了,但在我们现在正在进行的项目中,这种模式或多或少地被“成功”使用了。这是有道理的!我现在正忙着,所以我将把承诺中的承诺作为另一个可选答案发布。我回家后要试试你的方法。如果它有效并且可读性更好,我将奖励你的答案:)再次感谢你花时间回复。@tsurantino,当然没问题!希望你能找到一个合适的解决方案。我目前正在考虑在一个承诺中做一个承诺(所以我会做Q.all(geoQueries))。你认为这个解决方案比你的有什么优点?还有,为什么forEach不能像map那样在异步回调中失败呢?@tsurantino,我尽量避免使用承诺中的承诺方法,因为它通常会非常不可读。我认为
forEach
不会“失败”,因为
then
内部的回调只是存储对当前迭代的
业务的引用,当承诺解决时,它调用适当的回调并映射到适当的对象。我可能错了,但在我们现在正在进行的项目中,这种模式或多或少地被“成功”使用了。这是有道理的!我现在正忙着,所以我将把承诺中的承诺作为另一个可选答案发布。我回家后要试试你的方法。如果它有效并且可读性更好,我将奖励你的答案:)再次感谢你花时间回复。@tsurantino,当然没问题!希望你能找到一个合适的解决方案。