What I want to do is load a bunch of addresses using AJAX and JSON, find out the latitude and longitude of each address, put markers on the map and then use fitBounds(
The easy way of doing it to define your bounds object in global scope at the top with the other variables, and then construct it with each result as it's found (inside the geocoder callback).
Basically, everything you want to do with callback data needs to be in the callback or a function triggered by the callback (as you found). But in this case you don't need a separate function. The browser should store up all the fitBounds operations and do only the last one.
var latLng = new google.Maps.LatLng(
results[0].geometry.location.lat(),
results[0].geometry.location.lng());
marker_bounds.push(latLng);
latlngbounds.extend(latLng);
map.fitBounds(latlngbounds);
If necessary (because your browser is fast enough to do the fitBounds for every address), you could keep track of how many results have actually been returned in another variable, like your address_count, and test whether you have all the results before doing the fitBounds. That is, your subsidiary function can be incorporated into the geocoder callback.
var latLng = new google.Maps.LatLng(
results[0].geometry.location.lat(),
results[0].geometry.location.lng());
marker_bounds.push(latLng);
latlngbounds.extend(latLng);
address_count++;
if (address_count == data.addresses.length) map.fitBounds(latlngbounds);