function v1 executes w/o error, and console log shows the expected array populated w/ the response data. However, I'm trying to make life simpler down the road by returning 2 arrays within nysQueryReturn as an object:
function v2 also executes without errors, but console logs show
nysQueryReturn {sldlBills: Array(0), slduBills: Array(0)}...empty arrays.
Function v1: works as expected
function getBillData() {
return getBills().
then(function(response) {
// save retrieved bill numbers
var billData = response;
var nysQueryReturn = [];
// get NY State Leg data for each bill number
billData.forEach(function(p) {
// Assembly bill
nysBillQuery(p.gsx$sessionyear.$t, p.gsx$assemblynum.$t).
then(function(response){
nysQueryReturn.push(response);
});
// Senate bill
nysBillQuery(p.gsx$sessionyear.$t, p.gsx$senatenum.$t).
then(function(response){
nysQueryReturn.push(response);
});
});
console.log('nysQueryReturn', nysQueryReturn);
return nysQueryReturn;
});
} // end of getBillData()
function v2: empty arrays :(
function getBillData() {
return getBills().
then(function(response) {
// save retrieved bill numbers
var billData = response;
var nysQueryReturn = {
sldlBills: [],
slduBills: []
};
// get NY State Leg data for each bill number
billData.forEach(function(p) {
// Assembly bill
nysBillQuery(p.gsx$sessionyear.$t, p.gsx$assemblynum.$t).
then(function(response){
nysQueryReturn.sldlBills.push(response);
});
// Senate bill
nysBillQuery(p.gsx$sessionyear.$t, p.gsx$senatenum.$t).
then(function(response){
nysQueryReturn.slduBills.push(response);
});
});
console.log('nysQueryReturn', nysQueryReturn);
return nysQueryReturn;
});
} // end of getBillData()
i've found several examples of "array of arrays" and "array of objects" on stackoverflow, but i can't see how to re-purpose those answers to fit my "object of arrays" scenario. any thoughts/pointers/explanations of what i'm missing would be warmly welcomed.
Thank you for your time.
edit:
k, I found this question & answer, which seems to suggest I was "doing it right". Taking another look, Chrome Dev Tools console reports that the two arrays are "empty", but when expanded they contain the expected info. Still, I can't actually access the array elements w/ nysQueryReturn.sldlBills[0].basePrintNo
without getting TypeError: Cannot read property 'basePrintNo' of undefined
, and I can't for the life of me figure out why.
What am I not getting?
I will assume you know about arrow functions and how to use them appropriately. I will also assume you know about let
and const
. None of these are required, they just make things a little prettier. You can replace all arrow functions (in the example below) with normal functions and all let
and const
declarations with var
declarations.
Your end result should look something like the following:
function getBillData() {
return getBills().then((billData) => {
const nysQueryReturn = {
sldlBills: [],
slduBills: []
};
// This should look familiar, it returns a Promise. This
// Promise first loads the Assembly bill then adds the result
// to the appropriate array in nysQueryReturn object.
const loadAssemblyBill = (bill) => {
return nysBillQuery(bill.gsx$sessionyear.$t, bill.gsx$assemblynum.$t).then((sldlBill) => {
nysQueryReturn.sldlBills.push(sldlBill);
});
};
// This should look familiar, it returns a Promise. This
// Promise first loads the Senate bill then adds the result to
// the appropriate array in nysQueryReturn object.
const loadSenateBill = (bill) => {
return nysBillQuery(bill.gsx$sessionyear.$t, bill.gsx$senatenum.$t).then((slduBill) => {
nysQueryReturn.slduBills.push(slduBill);
});
};
// First exciting thing: Let's map each bill to a 2 workers
// that will load the important information that we will add to
// nysQueryReturn.
const workers = [];
billData.forEach((bill) => {
workers.push(loadAssemblyBill(bill));
workers.push(loadSenateBill(bill));
});
// Return a Promise that will wait for all the workers to
// finish.
return Promise.all(workers).then(() => nysQueryReturn);
});
}
You weren't seeing the results you expected because you weren't waiting for the results to load. In fact, if you set a timeout and examine the result sometime later, you would have seen the arrays populate.
Let's think of nysQueryReturn
as a box that holds all the sldlBills
and slduBills
, Promises as workers, and the code that called getBillData()
as your customer. With v2 of getBillData()
, you
nysQueryReturn
boxUnfortunately, you did not wait for your workers to finish their job before you gave the box to your customer. Needless to say, your customer was quite confused and just pretended like they got what they wanted.
With the new implementation, you
nysQueryReturn
boxYou wait for your workers to finish by maintaining a list of the workers
and then waiting for all()
(Promise.all()
) of them to tell you they have finished and added their results to the nysQueryReturn
box. After they have all finished, you give your customer all of the results (.then(() => nysQueryReturn)
).
Remember, every time you use a Promise
(anything that has a .then()
method), you are executing something outside of the flow of the normal program. JS will not wait for that flow to finish before continuing with it's original flow. Pictorially, this would look something like:
___________ ____________ ____________
| Flow 1 | | Flow 2 | | Flow 3 |
----------- ------------ ------------
billData.forEach(/* ... */);
console.log(/*...*/);
return nysQueryReturn;
nysQueryReturn.sldlBills.push(/*...*/);
nysQueryReturn.slduBills.push(/*...*/)
To wait for the new flow to finish, you have to explicitly wait for it by passing a callback to .then()
.