首页 > 解决方案 > 如何将异步信息添加到全局数组?

问题描述

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

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

到目前为止我的代码。

//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 的 API

标签: javascriptnode.jsrest

解决方案


仅供参考,albIds不是全球性的。它是一个模块范围的变量。

然后,您需要了解await只有在等待与异步操作完成相关的承诺时才会做一些有用的事情。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();

变更摘要:

  1. 切换到使用 promise 来传达结果并自动检查 2xx 状态的 request-promise 库。这与函数更兼容,async我们可以使用await它。
  2. 将其albIds作为已解决的值,getAlbums()而不是更高范围的共享变量(更不受并发问题的影响,并确保您在它准备好之前无法尝试使用它)。
  3. fetchUsers()中,使用albIds来自返回的承诺的getAlbums().
  4. 将所有变量更改为let或酌情更改(此处const根本不需要使用)。var
  5. 在 request-promise 调用上使用await以简化代码流并与返回的 promise 兼容getAlbums()

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

请参阅我应该为新项目使用“请求”模块吗?了解更多信息。


推荐阅读