Marco A. Ferra
Marco A. Ferra

Reputation: 193

d3.js v5 - Promise.all replaced d3.queue

I've been using d3.js v4 for sometime now and I've learned that Mike Bostock has replaced the d3.queue in the v5 release with the Promise native JavaScript object. I would like to check with you if this code that I have written is properly queuing (asynchronously) these URL's:

var makeRequest = function() {
    "use strict";

    var bli = [
        "http://stats.oecd.org/sdmx-json/data/BLI2013/all/all",
        "http://stats.oecd.org/sdmx-json/data/BLI2014/all/all",
        "http://stats.oecd.org/sdmx-json/data/BLI2015/all/all",
        "http://stats.oecd.org/sdmx-json/data/BLI2016/all/all",
        "http://stats.oecd.org/sdmx-json/data/BLI/all/all"
    ];

    var promises = [];

    bli.forEach(function(url) {
        promises.push(
            new Promise(function(resolve, reject) {
                d3
                    .json(url)
                    .then(function(response) {
                        resolve(response);
                    })
                    .catch(function(error) {
                        console.log("Error on: " + url + ". Error: " + error);
                        reject(error);
                    });
            })
        );
    });

    Promise.all(promises).then(function(values) {
        console.log(values);
    });
};

makeRequest();

The code seems to function properly, but, is this proper code or is there a better way (a best practice approach) for queuing with Promise.all and d3.js? Is the catch error properly implemented?

Upvotes: 17

Views: 15188

Answers (3)

theBird
theBird

Reputation: 61

You can also add a formatting function for your data as such if you want to clean up your data to your preference. .then() will have your data in a nice array which you can use later.

const myData = d3.csv("data.csv", formatterFunction)
.then(data => /* do whatever*/ )

function formatterFunction(row){
  // do formatting
  return // formatted data
   }

Upvotes: 0

xy2_
xy2_

Reputation: 7162

Here's an approach with ES6 async functions and ES6 array destructuring:

async function chart() {
  const [first, second] = await Promise.all([
    d3.json('data1.json'),
    d3.json('data2.json'),
  ])
  console.log('data2.json :', second)
}

chart()

Upvotes: 1

Gerardo Furtado
Gerardo Furtado

Reputation: 102198

You can simplify that code a lot: you don't net to use new Promise with d3.json, since d3.json will itself create the promise.

So, you can just do:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];

files.forEach(function(url) {
    promises.push(d3.json(url))
});

Promise.all(promises).then(function(values) {
    console.log(values)
});

Or, if you're into the code golf, even shorter:

var files = ["data1.json", "data2.json", "data3.json"];

Promise.all(files.map(url => d3.json(url))).then(function(values) {
    console.log(values)
});

Since I cannot use JSON files in the S.O. snippet, check the console in this bl.ocks: https://bl.ocks.org/GerardoFurtado/f08993c9c729b0b3452ef1803ad9dcbf/c4b45c5acce6033085a667cbb7d34203d15de0f0

Upvotes: 27

Related Questions