Non-asynchronous calls

725 views
Skip to first unread message

Kyle Foreman

unread,
Jan 16, 2012, 6:59:34 AM1/16/12
to d3...@googlegroups.com
I've found a few instances in which I would prefer my calls to not be asynchronous. I know that in most cases async is better practice, but there are some times when it causes confusion. 

For instance, if I have a select element that queries a database and then transitions my charts based on the returned data, a user rapidly changing the menu options can end up with a visualization that is out of sync with the values displayed in the select element. 

In these instances, I've begun using jQuery's $.ajax() (http://api.jquery.com/jQuery.ajax/) instead of d3.json(), because it allows async: false. (It also has a nice feature that allows you to give an array of data elements to POST)

Is there a reason for only allowing async calls from d3.json()/.xml()/etc? 

Mike Bostock

unread,
Jan 16, 2012, 11:48:31 AM1/16/12
to d3...@googlegroups.com
You can use XMLHttpRequest directly if you insist on making synchronous calls.

However, I wouldn't recommend it; it blocks the entire browser until
the request completes. It'd be much better—for example—to make the
select menu disabled while the required file is loading, and then
undisable it when the file loads. That way, you prevent the user from
entering a conflicting state, but you don't lock up the entire browser
and you allow limited interaction.

Also, you may want to disable a "loading" state while you are loading files.

One feature I would like to add is a way to cancel outstanding
requests. I think it'd be pretty easy to return an object from d3.xhr
(and friends) that has an abort() method.

Mike

Kyle Foreman

unread,
Jan 16, 2012, 11:57:36 AM1/16/12
to d3...@googlegroups.com
Thanks Mike, I figured you were deliberately reluctant to enable such behavior. For now my data typically loads quickly enough (and there are only a couple users of this one, so they can just deal with it :) ) that allowing the tab to lockup is ok, but I'll play around with just disabling certain elements if it moves into production.

Nate Vack

unread,
Jan 16, 2012, 12:18:22 PM1/16/12
to d3...@googlegroups.com

It's not so much the hang while a working load works, it's the very
very long hang when a load *fails* for some reason.

If you're going to be in a "just don't worry about the warts" mode,
it's probably still better to be async with an
temporarily-inconsistent UI.

-n

Kyle Foreman

unread,
Jan 16, 2012, 12:55:20 PM1/16/12
to d3...@googlegroups.com
I have error handling in the callback, so I think that should take care of it, but yes, point taken. Thanks!

Mike Bostock

unread,
Jan 16, 2012, 1:03:14 PM1/16/12
to d3...@googlegroups.com
Also consider that even small files can load slowly in certain
environments, such as AT&T's EDGE network.

Mike

Eric

unread,
Mar 15, 2012, 3:50:46 PM3/15/12
to d3...@googlegroups.com
Not to revive an couple-month-old thread, but I have another solution that some users may find useful, one that doesn't require jQuery or manual XHR work.

In my implementation, I had 3 CSVs to load, each containing different data from different sources. In my main JS file, I load each with d3.csv, and each calls a function that will initiate my action after all are ready. Its not optimal, but works well when async calls are a hinderence.

var data1, data2, data3;
d3.csv('path/file1.csv', function(data) {
...manipulate my data in to data1 variable...
readyCheck('file1');
})

d3.csv('path/file2.csv', function(data) {
...manipulate my data in to data2 variable...
readyCheck('file2');
})

d3.csv('path/file3.csv', function(data) {
...manipulate my data in to data3 variable...
readyCheck('file3');
})

var readyFiles = {'file1': false, 'file2': false, 'file3': false};
function readyCheck(filename) {
readyFiles[filename] = true;

if (readyFiles['file1']==true && readyFiles['file2']==true && readyFiles['file3']==true) {
...begin drawing visualization...
}
}

David Deutsch

unread,
Mar 16, 2012, 10:57:50 AM3/16/12
to d3...@googlegroups.com
I had to solve another problem in my implementation - that I would load parts of one big repository of sales database. That means that multiple charts on a page could draw from the same set and I wouldn't want it to load the same dates over and over. So my implementation is both kind of a chart factory and a keeper of one canonical dataset. It's still WIP, particular to my application and I'm quite fresh to javascript, but I've tried to stick with some of the guidelines for reusable code:

https://github.com/daviddeutsch/d3-Stuff/blob/master/chartfactory.js

A usage example would be, if you had another class d3.chart.sunburst

var cf = d3.chart.factory()
.source("sales")
.canvas(200, 200, 10)
.target("div#mycanvas")
.range(    "2012-05-12 00:00:00'",
        "2012-06-12 23:59:59'")
.create("sunburst");

subsequent calls to cf stay in the same syntax, so if I want to draw from the same dataset and call up d3.chart.cellular:

cf.canvas(200, 200, 10)
.target("div#mycanvas2")
.range(    "2012-06-01 00:00:00'",
        "2012-06-22 23:59:59'")
.create("cellular");

...it wouldn't have to request data from the server at all.

cheers,
David

João Figueiredo

unread,
May 13, 2015, 5:24:25 AM5/13/15
to d3...@googlegroups.com
Hi,

Not to revive a couple of years old thread :) , but would you still apply this solution today?

I'm thinking of doing the same thing for d3.xml, but my problem is that I'm drawing inside the callback (as in http://jsfiddle.net/christopheviau/XnG6r/). But I have several SVG's I need to get, and when they get drawn asynchronously, using the same (properly filtered) dataset, things get messy as one would expect.

I was thinking of using this solution just to save the imported xml nodes, and then draw them all when its finished (hope this is possible).

Would you still recommend this kind of approach, or has d3 come up with some way to handle this in the meantime?
Reply all
Reply to author
Forward
0 new messages