D3 - Can't return data from json request?

I am trying to use d3.json()

inside a function to return data from the Spotify API given the artist id (e.g. 5K4W6rqBFWDnAN6FQUkS6x ), but I cannot figure out how to return the data efficiently. The function looks like

// Get artist related artist information
function relatedArtists(id){
  var jsonPromise = new Promise(function(resolve, reject) {
    // Async JSON request
    d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data){
      if(error) reject(error);
      resolve(data.artists);
    });
  });

  jsonPromise.then(function(success) {
    console.log(success);
    //return(success)  //doesn't work
  });

  jsonPromise.catch(function(error){
    console.error(error);
  });

}

      

I tried to create a variable inside a function and then change it

function relatedArtists(id){
  var testVar = 'hello';
  var jsonPromise = new Promise(...{
    // Async JSON request
    d3.json(...)
  });
  jsonPromise.then(function(success) {
    testVar = success;
  });
  return(testVar);
}

      

But it testVar

remains 'hello'

, despite my best efforts. I've read about scope and promises, but I'm happy to do more if I have some basic mechanic that I don't understand. Thanks for reading!

+3


source to share


2 answers


You can return Promise

and use the function relatedArtists

like below



function relatedArtists(id) {
  return new Promise(function(resolve, reject) {
    d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data) {
      if (error) {
      	reject(error);
      } else {
      	resolve(data.artists);
      }
    });
  });
}


relatedArtists('5K4W6rqBFWDnAN6FQUkS6x')
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) {
    console.log(error);
  });
      

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
      

Run codeHide result


In this case, you cannot assign a value testVar

because it d3.json

is an asynchronous method, which means it d3.json

can be executed after the code has run.

+3


source


The answer will not be available in your calling code due to the asynchronous nature of the requests. You can use Promises (as Alexander T. suggested, and you are a good choice in many cases!) But d3.queue

does a good job too. In my snippet, you can see how to run the code with the results of multiple requests.



function buildRelatedArtistUri(id) {
  return 'https://api.spotify.com/v1/artists/' + id + '/related-artists';
}

d3.queue()
  .defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
  .await(function(error, data) {
    // data and data.artists are available in this functionβ€˜s scope only
    console.log(data.artists);
  });

d3.queue()
  .defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
  .defer(d3.json, buildRelatedArtistUri('3nFkdlSjzX9mRTtwJOzDYB'))
  .await(function(error, data1, data2) {
    // this function will be called once both functions have finished
    console.log(data1.artists, data2.artists);
  });
      

<script src="https://d3js.org/d3.v4.min.js"></script>
      

Run codeHide result


+4


source







All Articles