0

I have a file data.json with the contents: {"id": "foo", "value": "bar"}. I have another file index.html in the same directory with the following contents:

<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
  var datavar;
  d3.json("data.json", function(d) { datavar = d; console.log(datavar); });
  console.log(datavar);
</script>

When I open index.html in a web browser, the first console.log(datavar) call outputs {id: "foo", value: "bar"}. The second one outputs undefined. I was under the impression that since I initialized datavar outside of the function, changes I make to it would last once we're back out of the function. How can I store data from within the function that lasts outside the function?

Ben Lindsay
  • 1,686
  • 4
  • 23
  • 44
  • .json is probably an aysnc function. Reference [this question](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) or use Promises to fix this (nicely) – Sterling Archer Jan 20 '16 at 22:42
  • you might understand this better if you also log the exact time these fire, because what you think is the second log is, timewise, the first: `console.log(Date.now(), ":", datavar);` (the d3 function is invoked, but the callback won't run until d3 triggers it. It immediately exits the main call, and you hit console.log for a var which at that point has not been initialised yet) – Mike 'Pomax' Kamermans Jan 20 '16 at 22:44

2 Answers2

3

You are correct in your assumption that a variable defined at the global level, and then changed within a function will persist the change outside of said function.

However, this is outputting 'undefined' because it is an asynchronous operation. This means that the code changing 'datavar' may not have executed before you log it. If you add a note to your console logs, i.e. console.log('inside d3', datavar) and console.log('outside d3', datavar) you may be surprised to see the 'outside d3' execute first.

Async loading is most definitely what you want - so you should tailor your actual code accordingly. Please feel free to provide more details if you run into issues.

If you absolutely need to load the data synchronously, see this SO answer: How do I load JSON data synchronously with d3.js?

Community
  • 1
  • 1
ginman
  • 1,315
  • 10
  • 20
1

Your assumption that because the variable is initialized outside of the function it will be stored longer than the function is correct. What is incorrect is the order in which they get hit. d3.json calls an asynchronous function, which lets the rest of the application keep running while loading. So the console.log after the d3.json call happens (undefined), and then at some later time the data.json is loaded and the correct info is logged.

If you want to use this data you need to wait for it to return and only use it in a callback function. The way you are currently setting the variable will work, but you'd have to tell any code using it to re-run so it runs after the data from the file is loaded.

Alex Taker
  • 203
  • 1
  • 6