变量未定义 node.js

3
我正在尝试使用Node.js从API获取响应,我想要清洁API响应并使用结果。
所以为了访问第一个API,我有以下代码。
为了存储和使用结果,我相信我需要全局存储JSON输出。
但是,我无法弄清楚如何实现这一点。
例子 -
var request = require('request');

request({url: 'https://www.car2go.com/api/v2.1/vehicles?loc=wien&oauth_consumer_key=car2gowebsite&format=json', json: true}, function(err, res, json) {
if (err) {
    throw err;
}
car2go = json.placemarks;
for (i = 0; i < car2go.length; i++) {
    delete car2go[i].address;
    delete car2go[i].charging;
    delete car2go[i].exterior;
    delete car2go[i].interior;
    delete car2go[i].smartPhoneRequired;
    delete car2go[i].vin
    car2go[i].vendor = 'car2go';
    car2go[i].city = 'wien';
    car2go[i].carmake = 'Smart';
    car2go[i].carmodel = 'Fortwo';
}
console.log(car2go);
});

这将输出所需结果,但我知道这是因为我的变量是在函数内定义的。
我想在函数外部访问变量。
为了测试是否可以这样做,我更改了代码为-
var request = require('request');

request({url: 'https://www.car2go.com/api/v2.1/vehicles?loc=wien&oauth_consumer_key=car2gowebsite&format=json', json: true}, function(err, res, json) {
if (err) {
    throw err;
}
car2go = json.placemarks;
for (i = 0; i < car2go.length; i++) {
    delete car2go[i].address;
    delete car2go[i].charging;
    delete car2go[i].exterior;
    delete car2go[i].interior;
    delete car2go[i].smartPhoneRequired;
    delete car2go[i].vin
    car2go[i].vendor = 'car2go';
    car2go[i].city = 'wien';
    car2go[i].carmake = 'Smart';
    car2go[i].carmodel = 'Fortwo';
}
});

console.log(car2go);

但如果我这样做,我会得到:


ReferenceError: car2go is not defined

我在Mac OS Yosemite(10.10.3)上运行Node v0.12.2。

诚然,我对Node很陌生,更熟悉R、Python和PL SQL。

2个回答

1
由于console.log行在回调函数被调用之前运行,因此无法在回调函数外部获取对它的引用。你必须将回调函数传递到请求API中的原因是因为请求库需要在完成请求时调用该函数。同时,当等待回调函数触发时,你的应用程序会继续执行其他操作(例如运行那个console.log行)。
话虽如此,有许多处理异步代码的方法。我最喜欢的方法是使用promises。我使用一个叫做bluebird的库来处理promises。
var request = require('request');
var Promise = require('bluebird');
var requestP = Promise.promisify(request);

调用 Promise.promisify(request) 返回一个新的函数,该函数不需要回调函数,而是返回一个 promise
requestP({ url: 'https://www.car2go.com/api/v2.1/vehicles?loc=wien&oauth_consumer_key=car2gowebsite&format=json', json: true })
  .spread(function(res, json) {
    var car2go = json.placemarks;
    for (i = 0; i < car2go.length; i++) {
      delete car2go[i].address;
      delete car2go[i].charging;
      delete car2go[i].exterior;
      delete car2go[i].interior;
      delete car2go[i].smartPhoneRequired;
      delete car2go[i].vin
      car2go[i].vendor = 'car2go';
      car2go[i].city = 'wien';
      car2go[i].carmake = 'Smart';
      car2go[i].carmodel = 'Fortwo';
    }
  })
  .then(function (car2go) {
    console.log(car2go);
  })
  .catch(function (err) {
    console.error(err);
  });

Note: .spread is the same as .then except if the resolved value is an array (which it will be because the callback passed to the request library accepts 2 arguments, which bluebird will translate into an array that the promise resolves to) .spread will split up the array back into multiple arguments passed into the function you give to .spread.

Promise.resolve(['hi', 'there']).then(function (result) {
  console.log(result); // "['hi', 'there']"
});

Promise.resolve(['hi', 'there']).spread(function (str1, str2) {
  console.log(str1); // 'hi'
  console.log(str2); // 'there'
});
你无法将该值完全返回到开始异步调用的同一上下文中,但至少在使用 promises 时,你可以编写看起来有些同步的代码。
如果没有 promises,你将被迫从函数内部调用函数,再从函数内部调用函数,再从函数内部调用函数......

1
感谢您的出色回应。这仍然意味着,如果我想要进一步处理我的JSON数据,我要么必须在请求函数内调用一个函数,要么就必须继续将我的工作嵌套到当前代码中。 - rossi_182
没错。这就是为什么有了 Promise,我们才能保留一些我们习惯的东西,比如 try/catch,并防止由于不断嵌套回调而产生的“回调地狱”。 - Chev
具有讽刺意味的是,今天早上我读了一篇关于 Promises 的非常精彩的博客文章。我建议你去看看 :D。这篇文章并不是真正意义上的教学,但它展示了一些很棒的例子,并强调了一些优秀的初学者错误。http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html - Chev

0

响应是异步的。这意味着回调函数将在未来的某个时间被调用,因此您的console.log(car2go)在回调甚至被调用之前就已经执行了。

您唯一可以可靠使用响应的地方是在回调内部或从回调中调用的函数中。您不能像尝试的那样使用它。在JavaScript中使用异步响应需要以异步方式编程,这意味着仅在异步回调中处理结果和使用结果。

这里是console.log()应该放置的位置:

var request = require('request');

request({url: 'https://www.car2go.com/api/v2.1/vehicles?loc=wien&oauth_consumer_key=car2gowebsite&format=json', json: true}, function (err, res, json) {
    if (err) {
        throw err;
    }
    car2go = json.placemarks;
    for (i = 0; i < car2go.length; i++) {
        delete car2go[i].address;
        delete car2go[i].charging;
        delete car2go[i].exterior;
        delete car2go[i].interior;
        delete car2go[i].smartPhoneRequired;
        delete car2go[i].vin
        car2go[i].vendor = 'car2go';
        car2go[i].city = 'wien';
        car2go[i].carmake = 'Smart';
        car2go[i].carmodel = 'Fortwo';
    }
    // here is where the result is available
    console.log(car2go);
});

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Chev
1
@AlexFord - 是的。我已经删除了答案中的那部分内容。 - jfriend00
@tadman - 你是不是把评论放错地方了?我不知道32位整数和我的回答有什么关系。 - jfriend00
1
我猜我的笑话,即一个万亿无法在32位整数中表示的说法并没有起作用。 - tadman
@tadman - 这个我没看懂。不管怎样,我的回答里的那个“zillion”评论已经被编辑掉了一段时间了。 - jfriend00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接