How Fast Is Netlify + DataStax Astra?
Join a JavaScript newbie’s journey to understanding async and await in this post — a live web app that times how long it takes to make asynchronous API calls.
After my first introduction to JavaScript about six months ago, I wanted to reach a deeper understanding of the built-in asynchronous programming concepts within the JavaScript language: async
, await
, and promises
. To teach myself these concepts, I came up with a close to real-world, testable question for this live app:
There are many, many ways we can do this. This post (which is a real, live app) focuses on timing the roundtrip API calls between two different cloud-based services:
The rest of this post details how I set up the timing tests using asynchronous API calls, and a few hiccups I ran into along the way. Go here for a 10-minute tutorial on how to set up Netlify functions to make API calls to an Astra database.
How do we set up asynchronous timing tests?
Let’s set up 10 tests. Each test will make 10 asynchronous (in parallel or simultaneous) API calls to our database in Astra DB. Our goal is to time the round trip for each set of asynchronous API calls from a simple web app to our cloud database and back. The pseudocode for this would look like this:
- 1
- 2
- 3
- 4
- 5
- 6
1 Write a function to run multiple rounds of tests 2 For each round of testing 3 Start a timer in the app 4 Call a function that will perform asynchronous API calls 5 Stop the timer in the app 6 Display the total time for that round
The above pseudocode translates into the following JavaScript:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
1 function runTests(rounds, numberAPICalls) { 2 for (round = 0; round < rounds; round++) { 3 var startTime = new Date(); 4 timeTest(numberAPICalls).then(() => { 5 var finishTime = new Date(); 6 var timeTaken = finishTime - startTime; 7 ); 8 } 9}
The work of doing the asynchronous API calls is in the timeTest
function; we will get to what that does after we take a look at my first mistake.
Click the link below to run this web app’s timing suite with the function definition above. Before reading the answer written below the output, can you see what is wrong with the output?
What’s wrong with these results?
There are two glaring mistakes with the output on the other page that led me to think we weren’t setting this up correctly. First, the round
number is the same for each series of tests. Second, the startTime
is the exact same for each test.
Something isn’t right here. It seems like the round
number and the startTime
are not updating with each subsequent series of tests. Instead, we want both the round
number and startTime
to wait for the tests to complete before changing the value.
This is where we run into the async
and await
a pattern in JavaScript.
What is the async
/ await
pattern and how do we use it here?
Think of async
and await
as making the code read synchronously (like Python), even though it really isn’t. This great blog by Mozilla details the definitions and usages of the async
/await
pattern. The definition of await
is:
await
can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.We need to pause our code after the test so that the timer can correctly calculate the runtime for each set of asynchronous API calls. Let’s change the function above into an async
function and tell the code to pause for the entire set of API calls to finish with await
before stopping the timer. This changes the function to the following:
1 async function runTests(rounds, numberAPICalls) { 2 for (round = 0; round < rounds; round++) { 3 var startTime = new Date(); 4 await timeTest(numberAPICalls).then(() => { 5 var finishTime = new Date(); 6 var timeTaken = finishTime - startTime; 7 ); 8 } 9 }
Click the link below to see the results when using the above structure for your testing skeleton:
Great! This testing suite is now properly timing only one round of API calls at a time. Last up, let’s take a look at how we are making the API calls.
How do you kick off a bunch of asynchronous API calls?
I love how easy it is to use Netlify’s functions feature. For this project, I created one REST API to make calls from Netlify to the database in Astra. In the timing suite, the API call is made in one async
function which waits for the payload to return. You can see the same async/await
pattern in the function below to make the API call and wait for the result:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
1const addData = async (testNumber) => { 2 const response = await fetch("/.netlify/functions/writeRestAPI", { 3 method: "POST", 4 body: testNumber, 5 }); 6 const responseBody = await response.json(); 7};
The last step in our setup is to make simultaneous calls to this API. We need one last async
function for this:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
1 async function timeTest(numTests) { 2 const dataPromises = []; 3 for (let i = 0, ilen = numTests; i < ilen; i++) { 4 dataPromises.push(addData(i)); 5 } 6 return await Promise.all(dataPromises); 7}
I bolded two sections in the above code snippet. First, let’s look at Promise.all()
. This is the final piece of key functionality for our testing. The use of Promise.all()
here will wait for all asynchronous API calls to return before returning the results.
You can find all of the code for this project here.
Follow the DataStax Tech Blog for more developer stories. Check out our YouTube channel for tutorials and here for DataStax Developers on Twitter for the latest news about our developer community.
Resources
- JavaScript
- Netlify
- DataStax Astra DB
- Github Repository: Todo list JAMStack app example with ReactJS + DataStax Astra DB
- Making asynchronous programming easier with async and await
- Netlify Functions
- Github Repository: Creating a REST API to make calls from Netlify to Astra DB
- Github Repository: Testing API speed for Astra DB in a variety of scenarios