我正在学习Node JS以及如何访问API的信息,并且遇到一个问题,当我将值推入数组时,信息永远不会在全局范围内添加。
假设我有var albIds= new Array(5)
,则永远不会添加值。通过查看this和this现在,我知道问题在于,由于首先完成了同步代码,所以信息在我调用它时从未进入数组,但是,我对如何使信息感到困惑同步等待异步完成。
到目前为止,我的代码。
//prints out albums 1-5 id's
var id = '3TVXtAsR1Inumwj472S9r4';
var albIds= new Array(5);
async function getAlbums(i) {
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: {
'Authorization': 'Basic ' + (new Buffer.from(client_id + ':' + client_secret).toString('base64'))
},
form: {
grant_type: 'client_credentials'
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
// use the access token to access the Spotify Web API
// const querystring = require('querystring');
const data = {
market: "US",
limit: "5"
};
const q = querystring.stringify(data);
var token = body.access_token;
var options = {
url: 'https://api.spotify.com/v1/artists/'+id+'/albums?'+q,
headers: {
'Authorization': 'Bearer ' + token
},
json: true
};
request.get(options, function(error, response, body)
{
for(var i = 0; i<5;i++)
{
albIds.push(body.items[i].id);
}
});
}
})
};
async function fetchUsers()
{
for(var i = 0;i<5;i++)
{
await getAlbums(i);
console.log(albIds[i]);
}
}
fetchUsers();
任何帮助表示赞赏。供参考,我使用的是Spotify's API
最佳答案
仅供参考,albIds
不是全局变量。这是模块范围的变量。
然后,您需要了解await
仅在等待与异步操作完成有关的Promise时才有用。 getAlbums()
函数不是这种情况。虽然它声明为async
,所以它确实返回了一个Promise,但该Promise根本不与您完成异步操作有关。
相反,在将任何数据放入albIds
数组之前很久,诺言就完成了。因此,您认为该数组为空(因为在尝试使用它时尚未放入任何内容)。
这是我的建议:
const rp = require('request-promise');
//prints out albums 1-5 id's
const id = '3TVXtAsR1Inumwj472S9r4';
async function getAlbums(i) {
const albIds = new Array(5);
const authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: {'Authorization': 'Basic ' + (new Buffer.from(client_id + ':' + client_secret).toString('base64'))},
form: {grant_type: 'client_credentials'},
json: true
};
const body = await rp.post(authOptions, function(error, response, body) {
const data = {
market: "US",
limit: "5"
};
const q = querystring.stringify(data);
const token = body.access_token;
const options = {
url: 'https://api.spotify.com/v1/artists/' + id + '/albums?' + q,
headers: { 'Authorization': 'Bearer ' + token },
json: true
};
let result = await rp.get(options);
for (let j = 0; j < 5; j++) {
albIds.push(result.items[j].id);
}
// let resolved value be the array
return albIds;
};
async function fetchUsers() {
for (let i = 0; i < 5; i++) {
const albiIds = await getAlbums(i);
console.log(albIds[i]);
}
}
fetchUsers();
变更摘要:
切换到使用Promise传递结果并自动检查2xx状态的请求承诺库。这与
async
函数更加兼容,我们可以将await
与它一起使用。将
albIds
设置为getAlbums()
的可解析值,而不是更大范围的共享变量(对并发问题具有更大的免疫力,并且可以确保在准备就绪之前不能尝试使用它)。在
fetchUsers()
中,使用来自albIds
返回的承诺的getAlbums()
。将所有变量适当地更改为
let
或const
(完全不需要在此处使用var
)。在请求承诺调用上使用
await
可以简化代码流,并与getAlbums()
返回的承诺兼容。仅供参考,如果这是相当新的代码,我将停止使用
request
或request-promise
库,因为它们已正式不推荐用于新开发。虽然将对其进行维护,但是随着时间的推移,它们将不会获得新功能。您可以了解发生这种情况的原因,但是基本上它们已经存在了很长时间,并且在那段时间node.js发生了很大的变化,以至于它们变得难以维护和向前发展。但是,有太多的用户,他们无法真正地对API进行重大更改,以使其真正继续向前发展(例如使其完全由承诺驱动)。而且,由于许多具有更好现代设计的好的替代品,他们决定将未来转向其他替代品。我个人将got()
用于大多数用途,但还有许多其他选择可供选择。有关更多信息,请参见Should I use the 'request' module for a new project?。