Oh man, in my React/Redux final project, which uses New York City’s open data to create a dashboard for city renters, I ended up having to chain a lot of API GET requests together because of the way the data was organized.
For instance, to get a building’s Registration Info (information about building owner and manager), I had to first lookup a building’s Building Identification Number (BIN) in one dataset, cross-reference than BIN with a Registration ID in another, and use the Registration ID in a third to finally come across the Registration Info.
And all that resulted in (assume fetchBin, fetchRegId, and fetchRegInfo are the appropriate API calls:
export function getRegistrationInfo(address) { return dispatch => { dispatch({ type: 'GET_BIN', address }); return fetchBin() .then( response => { dispatch({ type: 'GOT_BIN', address, response }); dispatch({ type: 'GET_REG_ID', address }); return fetchRegId() } ) .then( response => { dispatch({ type: 'GOT_REG_ID', address, response }); dispatch({ type: 'GET_REG_INFO', address }); return fetchRegInfo() } .then( response => { dispatch({ type: 'GOT_REG_INFO , address, response}); } ) } }
I just don’t like it. Maybe some people like chaining these Promises because it’s like a timeline or something, but I think it just looks bad!
Enter async
and await
. Unfortunately I didn’t know about them until my code review, but I wish I had! Introduced in ES2017, it’s a new way to handle asynchronous functions in JavaScript!
async
allows you to declare a function that will return a Promise. More importantly, async
functions can contain await
expressions that pauses execution while the expression is resolved. Using async/await, I could refactor the above code as follows:
export async function getRegistrationInfo(address) { return dispatch => { dispatch({ type: 'GET_BIN', address }); const binResponse = await fetchBin(); dispatch({ type: 'GOT_BIN', address, binResponse }); dispatch({ type: 'GET_REG_ID, address }); const regIdResponse = await fetchRegId(); dispatch({ type: 'GOT_REG_ID', address, regIdResponse }); dispatch({ type: 'GET_REG_INFO, address }); const regInfoResponse = await fetchRegInfo(); dispatch({ type: 'GOT_REG_INFO, address, regInfoResponse }); } }
To me, that looks so much better and simpler. I understand there are some difficulties with error catching when using async
/await
, which I’ll have to look more into. And I admit that my Promise chaining did not look as neat as the example I have above, which isn’t that bad, because I hadn’t seen the proper way to do it, as detailed here. I had been indenting with every then
, which was just getting crazy…
Anyway, at least it’s another option I now know about!