for循环在节点js中返回null

时间:2017-03-13 19:06:52

标签: javascript node.js

我使用googles api获得3个字段, 名称评级和地点评论。由于地方审查使用另一个api调用我创建它作为一个函数来获取我的place_review中的数据。

response.results.forEach((entry)=>{
         var restaurantName = {
          "name" : entry.name,
          "rating" : entry.rating,
          "place_review" : placeReview(entry.place_id)
        }
        arr.push(restaurantName);
        console.log(restaurantName);// shows only name and rating
      });

额外功能

function placeReview(place_id){
   console.log(place_id) // i see all place id via forloop.
   googlePlaces.placeDetailsRequest({placeid: place_id},function(error,response){
    if (error) throw error;
     return response.result.reviews[0].text;
  });
}

当我运行代码时,我得到name : somenamerating : 4.5place_review : null

我以为forloop会调用该函数,函数的返回会将字符串追加到"place_review",不知道我做错了什么。

2 个答案:

答案 0 :(得分:0)

placeDetailsRequest api是异步的,这意味着它已启动但不会立即完成。因此,行:

return response.result.reviews[0].text;

没有意义,因为没有什么可以回归。

您的console.log(restaurantName);将在请求完成之前运行,因此您只能获得“未定义”。

要解决这个问题,你需要做一些更复杂的事情(假设,现在Promises是你不熟悉的东西,但这通常是人们对异步编程方式感到满意的方式作品):

response.results.forEach((entry)=>{
    var restaurantName = {
        "name" : entry.name,
        "rating" : entry.rating,
        "place_review" : undefined    // will be filled in later
    }
    placeReview(entry.place_id, restaurantName);
});

function placeReview(place_id, obj){
   console.log(place_id) // i see all place id via forloop.
   googlePlaces.placeDetailsRequest({placeid: place_id},function(error,response){
     if (error) throw error;
     obj.place_review = response.result.reviews[0].text;
     console.log(obj);
  });
}

当然,您只会在每个请求完成时看到控制台结果。

这使用一种称为“回调”的技术来管理仅在以后可用的信息。在线和SO上有很多关于此的信息。

这是一个可以运行以查看该技术的版本 - 与上述非常相似但是硬连接了一些数据。

var list = [
  { name: 'Aaron', rating: '14', place_id: 21 },
  { name: 'Brad', rating: '33', place_id: 33 }
];

list.forEach(function (entry) {
  var restaurantName = {
    "name" : entry.name,
    "rating" : entry.rating,
    "place_review" : undefined    // will be filled in later
  };
  placeReview(entry.place_id, restaurantName);
});

function placeDetailsRequest(idObj, cb) {
  setTimeout(function() {
    var result = (idObj.placeid === 21) ? 'def' : 'abc';
    cb(null, { result: { reviews: [{ text: result}]}});
  }, 2000);
}

function placeReview(place_id, obj) {
  console.log(place_id);  // i see all place id via for loop.
  placeDetailsRequest( { placeid: place_id }, function(error,response){
    if (error) throw error;
    obj.place_review = response.result.reviews[0].text;
    console.log(obj);
  });
}

进一步编辑以显示承诺解决方案:

var list = [
  { name: 'Aaron', rating: '14', place_id: 21 },
  { name: 'Brad', rating: '33', place_id: 33 }
];

var allPromises = list.map(function (entry) {
  var restaurantName = {
    "name" : entry.name,
    "rating" : entry.rating,
    "place_review" : undefined    // will be filled in later
  };
  return placeReview(entry.place_id, restaurantName);
});

Promise.all(allPromises)
  .then(results => console.log(results))
  .catch(error => console.log(error));

function placeReview(place_id, obj) {
  return new Promise((resolve, reject) => {
    // Here's where you would do your google api call to placeDetailsRequest
    // if error then reject the promise, otherwise resolve it with your results
    //googlePlaces.placeDetailsRequest({placeid: place_id},function(error,response){
    //  if (error) {
    //    reject(error);
    //  } else {
    //    obj.place_review = response.result.reviews[0].text;
    //    resolve(obj);
    //  }
    //});

    // simulating with delayed response
    setTimeout(() => {
      var result = (place_id === 21) ? 'def' : 'abc';
      obj.place_review = result;
      resolve(obj);
    }, 2000);
  });
}

还有其他方法可以解决这个问题,但在这个解决方案中,我正在使用已完成的对象解决这个问题。 Promise.all()函数then要么显示成功结果,要么catch会显示错误。

答案 1 :(得分:-1)

<强>承诺

您可以使用Q在您的地点审核功能中实施承诺:

function placeReview (place_id) {
  var deferred = Q.defer();
  googlePlaces.placeDetailsRequest({placeid: place_id},function(error,response){
    if (error) deferred.reject(err);
    else deferred.resolve(response.result.reviews[0].text);
  });
  return deferred.promise // the promise is returned
}

然后您可以在处理逻辑中调用该函数,如下所示:

response.results.forEach((entry)=>{
    placeReview(entity.place_id).then(function(text) {
      var restaurantName = {
         "name" : entry.name,
         "rating" : entry.rating,
         "place_review" : text
       }
       arr.push(restaurantName);
       console.log(restaurantName);// shows only name and rating
    });
  });

在您完成对API的调用之前,您不会推送餐厅的详细信息。

异步选项

您可以使用async协调来电:

每个条目都会执行一次此函数:

function placeReview(entry, callback){
   console.log(entry.place_id)
   googlePlaces.placeDetailsRequest({entry.placeid: place_id},function(error,response){
    if (error) throw error;
     //this call back retrives the restaurant entity that async stack in a list
     callback(null,{
        "name" : entry.name,
        "rating" : entry.rating,
        "place_review" : response.result.reviews[0].text
      });

  });
}

然后你要求async迭代你的结果数组并为每一个执行placeReview。 Async会在数组中收集结果:

async.map(response.results, placeReview, function(err, results) {
  // results will have the results of all 2
  console.log(results); //this is your array of restaurants
});