我试图通过Express.js框架学习Node.js。目前,我需要进行API调用以获取一些对我的应用程序有用的数据。
API调用是使用Request middleware进行的,但当我退出请求时,我的变量将变为未定义...让我告诉你:
var request = require('request');
var apiKey = "FOOFOO-FOOFOO-FOO-FOO-FOOFOO-FOOFOO";
var characters = [];
var gw2data;
var i = 0;
module.exports.account = function() {
request('https://api.guildwars2.com/v2/characters/?access_token=' + apiKey, function (error, response, body) {
gw2data = JSON.parse(body);
console.log('out request ' + gw2data); // {name1, name2 ...}
for (i; i < gw2data.length; i++) {
getCharacInfo(gw2data[i], i);
}
});
console.log('out request ' + characters); // undefined
return characters;
};
function getCharacInfo (name, position) {
request('https://api.guildwars2.com/v2/characters/' + name + '/?access_token=' + apiKey, function (error, response, body) {
if (!error && response.statusCode == 200) {
characters[position] = JSON.parse(body);
}
});
}
我不明白为什么当我退出请求时gw2data变量变得不确定...有人可以解释一下吗?
编辑:我来找你,因为我的问题已经改变了,我现在需要在我的第一个API调用中进行API调用循环,我想是同样的异步问题。
之前的代码已根据之前的答案进行了演变:
module.exports.account = function(cb) {
var request = require('request');
var apiKey = "FOOFOO-FOOFOO-FOO-FOO-FOOFOO-FOOFOO";
var characters = [];
var i = 0;
request('https://api.guildwars2.com/v2/characters/?access_token=' + apiKey, function(err, res, body) {
var numCompletedCalls = 1;
for (i; i < JSON.parse(body).length; i++) {
if (numCompletedCalls == JSON.parse(body).length) {
try {
console.log(characters); // {} empty array
return cb(null, characters);
} catch (e) {
return cb(e);
}
}else {
getCharacInfo(JSON.parse(body)[i]);
}
numCompletedCalls++;
}
});
};
function getCharacInfo (name) {
request('https://api.guildwars2.com/v2/characters/' + name + '/?access_token=' + apiKey, function (err, res, body) {
if (!err) {
console.log(characters); // {data ...}
characters.push(JSON.parse(body));
}
});
}
这个函数的调用:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
var charactersInfos = require('../models/account');
charactersInfos.account(function(err, gw2data) {
if (err) {
console.error('request failed:', err.message);
} else {
res.render('index', {
persos : gw2data
});
}
});
});
问题是,当我返回字符数组时,它总是一个空数组,但当我检查我的函数getCharacInfo时,数组包含数据......
答案 0 :(得分:1)
第二个gw2data
中undefined
为console.log
的原因是因为您过早登录。 request
是异步操作,因此它会立即返回 ...但是,这并不代表回调。
所以基本上你在实际设置之前记录gw2data
的做法是什么。在处理异步操作时,最好的方法是通常使自己的方法也是异步的,这可以通过几种方式实现 - 最简单的方法就是让你的函数接受一个以异步方式期望数据的回调,例如。
module.exports.account = function(cb) {
request(..., function(err, res, body) {
// return an error if `request` fails
if (err) return cb(err);
try {
return cb(null, JSON.parse(body));
} catch (e) {
// return an error if `JSON.parse` fails
return cb(e);
}
});
}
...
var myModule = require('mymodule');
myModule.account(function(err, g2wdata) {
if (err) {
console.error('request failed', err.message);
} else {
console.log('out request', g2wdata);
}
});
根据您的语法,我假设您不使用ES6,值得一看(特别是如果您刚刚开始学习)。内置承诺&amp; async-await支持相对很快这种东西变得相对简单(至少在主叫端),例如。
export default class MyModule {
account() {
// return a promise to the caller
return new Promise((resolve, reject) => {
// invoke request the same way but this time resolve/reject the promise
request(..., function(err, res, body) {
if (err) return reject(err);
try {
return resolve(JSON.parse(body));
} catch (e) {
return reject(e);
}
});
});
}
}
...
import myModule from 'mymodule';
// handle using promises
myModule.account()
.then(gw2data => console.log('out request', gw2data))
.catch(e => console.error('request failed', e));
// handle using ES7 async/await
// NOTE - self-executing function wrapper required for async support if using at top level,
// if using inside another function you can just mark that function as async instead
(async () => {
try {
const gw2data = await myModule.account();
console.log('out request', gw2data);
} catch (e) {
console.log('request failed', e);
}
})();
最后,如果您决定沿着Promise路线前进,那么有几个库可以将Promise支持填充到现有库中。我能想到的一个例子是Bluebird,根据我所知道的经验与request
一起工作。将其与ES6相结合,您将获得非常简洁的开发人员体验。
答案 1 :(得分:0)
请求API是异步的,因为Node.js中的所有I / O都是异步的。查看Promise API是IMO编写异步代码的最简单方法。有一些Promise适配器可用于请求,或者您可以使用superagent之类的promise支持。