How to Perform Multiple Asynchronous Tasks with D3

This article explains how to use D3 to perform a set of tasks asynchronously and wait until those tasks have been completed before performing another task.

Loading CSV Data Asynchronously

I’ll use loading a CSV data set as an example of a task that can be performed asynchronously. D3 loads CSV data asynchronously using the d3.csv function:

d3.csv("path/to/file.csv", function(error, csvData) {
  if (error) throw error;
  // Process the CSV data
});

To simulate a list of CSV-loading tasks, we’ll create an array of filenames that correspond to files containing CSV data:

var filenames = [ "dataSet1.csv", "dataSet2.csv", "dataSet3.csv" ];

Queuing CSV-Loading Tasks

To perform tasks asynchronously using D3, we need to use the queue object provided by a separate D3 library called d3-queue, which can be installed using NPM, Bower or by downloading the latest release.

First, we create the D3 queue that will hold the asynchronous CSV-loading tasks:

var queue = d3.queue();

To build the queue of asynchronous tasks, we iterate over the array of CSV filenames. For each CSV filename, we use the queue’s defer method to add a call to the d3.csv function with the name of the next CSV file as a parameter:

filenames.forEach(function(filename) {
  queue.defer(d3.csv, filename);
});

Processing the Queue

After adding the asynchronous CSV-loading tasks, we call the awaitAll method to start processing the tasks on the queue. When all the asynchronous tasks have been completed, the awaitAll method calls the anonymous callback function. Each data set loaded from the CSV files is stored as an element of the dataSets array:

queue.awaitAll(function(error, csvDataSets) {
  if (error) throw error;
  // csvDataSets is an array of CSV data
});

Accessing the CSV Data

We can access each CSV data set either by indexing the csvDataSets array (e.g. csvDataSets[0]) or by iterating over each element:

csvDataSets.forEach(function(csvDataSet) {
  // Process the CSV data
});

It Works With JSON Too

Although I’ve used loading CSV files with the d3.csv function, this technique also works with other functions that have the same signature as d3.csv, such as d3.json, which loads JSON data:

d3.json("path/to/file.json", function(error, jsonData) {
  if (error) throw error;
  // Process the JSON data
});

Asynchronous JSON-loading tasks are queued in the same way as CSV-loading tasks, i.e. by calling queue.defer with the d3.json function and the name of a JSON file:

filenames.forEach(function(filename) {
  queue.defer(d3.json, filename);
});