0

I'm following along in Adam Janes's choropleth tutorial.

The data is loaded with this code block

var promises = [
  d3.json("https://d3js.org/us-10m.v1.json"),
  d3.tsv("unemployment.tsv", function(d) { unemployment.set(d.id, +d.rate); })
]

Promise.all(promises).then(ready)

And ready is defined as

function ready([us]) {
  svg.append("g")
      .attr("class", "counties")
    .selectAll("path")
    .data(topojson.feature(us, us.objects.counties).features)
    .enter().append("path")
      .attr("fill", function(d) { return color(d.rate = unemployment.get(d.id)); })
      .attr("d", path)
    .append("title")
      .text(function(d) { return d.rate + "%"; });

  svg.append("path")
      .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
      .attr("class", "states")
      .attr("d", path);
}

I understand this sequence as

first - make an array called promises where the first item is the parsed json from this link and the second item is a map with id/value pairs from the unemployment file

second - grab all promises in the promise variable and, if it succeeds, then trigger the function ready and if it fails, do nothing

If that's right, then what's the advantage over something like this? I'm writing this in pseudo code because I'm new to this

var promises = [
  d3.json("https://d3js.org/us-10m.v1.json"),
  d3.tsv("unemployment.tsv", function(d) { unemployment.set(d.id, +d.rate); })
]

if(promises == 'SUCCESS'){ function(ready) };

Just a note, I read about promises and their advantage since javascript is single-threaded. I ask this question since it doesn't strike me that anything asynchronous is happening, the code has to load the promises array in both cases.

Sebastian
  • 957
  • 3
  • 15
  • 27

2 Answers2

3

d3.json() and d3.tsv() are both asynchronous network calls; those promises will resolve when the calls are complete. Your pseudocode wouldn't work because the if would run immediately after the async calls are made, not after they're finished.

Promises are a way of saying "Do this thing that will take a while, then when it's done do something with its results". (As pointed out in comments, this is a simplified definition but it's probably enough to get started with.) A synchronous version of that would be "do this thing that will take a while, then immediately try to do something with the results (that haven't arrived yet)."

Promise.all(promises).then(ready);

In this case you actually have promises wrapped inside another promise -- the two d3 calls are each a promise, then Promise.all() wraps another promise around both of them, which will wait until both of the inner ones are complete before firing its then().

This has nothing to do with javascript being single-threaded; it just changes the order of events. To clarify:

console.log("Before promises");
Promise.all(promises).then(function() {
   console.log("Promises have resolved");
});
console.log("After promises");

would result in this output:

> Before promises
> After promises
> Promises have resolved
Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
  • 2
    "Promise.all(promises) will begin both of those async calls". Not as I understand it. Those promises have already been started - `Promise.all` simply waits for them to all to either resolve or reject. – Andy Feb 03 '19 at 19:55
  • Ah, yeah, I oversimplified. I'll expand the answer, you're right. – Daniel Beck Feb 03 '19 at 19:56
  • "*Do this thing that will take a while, then when it's done do something with its results*" - sounds like you are describing asynchronous callbacks in general, not promises in particular. – Bergi Feb 03 '19 at 19:58
  • @Bergi for the purposes of this answer I think that's the most important part, yeah; the finer details would be more confusing than helpful to someone at this level. – Daniel Beck Feb 03 '19 at 20:05
2

it doesn't strike me that anything asynchronous is happening

There's your mistake. d3.json and d3.tsv are both asynchronous calls, they load files from the web.

make an array where the first item is the parsed json and the second item is a map

No. The calls return promises, not results that are immediately available and could be checked for their success synchronously. You might want to refresh your knowledge on what a Promise object represents.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375