我正在学习Node JS以及如何访问API的信息,并且遇到一个问题,当我将值推入数组时,信息永远不会在全局范围内添加。

假设我有var albIds= new Array(5),则永远不会添加值。通过查看thisthis现在,我知道问题在于,由于首先完成了同步代码,所以信息在我调用它时从未进入数组,但是,我对如何使信息感到困惑同步等待异步完成。

到目前为止,我的代码。

//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()
将所有变量适当地更改为letconst(完全不需要在此处使用var)。
在请求承诺调用上使用await可以简化代码流,并与getAlbums()返回的承诺兼容。




仅供参考,如果这是相当新的代码,我将停止使用requestrequest-promise库,因为它们已正式不推荐用于新开发。虽然将对其进行维护,但是随着时间的推移,它们将不会获得新功能。您可以了解发生这种情况的原因,但是基本上它们已经存在了很长时间,并且在那段时间node.js发生了很大的变化,以至于它们变得难以维护和向前发展。但是,有太多的用户,他们无法真正地对API进行重大更改,以使其真正继续向前发展(例如使其完全由承诺驱动)。而且,由于许多具有更好现代设计的好的替代品,他们决定将未来转向其他替代品。我个人将got()用于大多数用途,但还有许多其他选择可供选择。

有关更多信息,请参见Should I use the 'request' module for a new project?

09-25 18:52
查看更多