- Null Pointer Club
- Posts
- Async/Await & Futures in Programming
Async/Await & Futures in Programming
Writing Non-Blocking Code That Performs Better and Reads Clean
As applications grow more interactive and connected, the need for responsive, efficient, and scalable systems becomes essential. That’s where non-blocking code comes in.
Instead of making your program wait (and waste time) while it fetches data or performs I/O operations, modern languages now offer tools like Futures, Promises, and async/await to keep your code flowing without freezing the thread.
In this issue of Nullpointer Club, we’ll break down what async programming is, why it matters, how Futures and async/await work, and when (and when not) to use them.
You found global talent. Deel’s here to help you onboard them
Deel’s simplified a whole planet’s worth of information. It’s time you got your hands on our international compliance handbook where you’ll learn about:
Attracting global talent
Labor laws to consider when hiring
Processing international payroll on time
Staying compliant with employment & tax laws abroad
With 150+ countries right at your fingertips, growing your team with Deel is easier than ever.
The Problem with Blocking Code
Let’s say your application needs to fetch data from a database, an API, or the file system. In traditional synchronous programming:
result = get_user_data() # blocks until response is ready
During this time, your thread does nothing else. If you're running a web server or UI thread, this blocks the entire application—even if the actual wait time is just a few milliseconds.
Multiply this by thousands of users or requests, and your system becomes sluggish or unresponsive.
Enter: Non-Blocking Code
Non-blocking programming allows you to initiate a task and move on to other work while it completes in the background.
This is especially powerful for:
Web servers (handling multiple requests efficiently)
UI apps (keeping interfaces smooth)
Data pipelines and async APIs
Futures: A Promise for Later
A Future represents a value that may not be available yet, but will be—eventually.
Think of it like ordering food at a restaurant: you place the order (start a task), and your waiter will bring it when it’s ready (the future completes). Meanwhile, you can talk, check your phone, or order dessert (do other work).
Example in Java:
CompletableFuture<String> future = getDataAsync();
future.thenAccept(data -> System.out.println("Got: " + data));
You're not blocking while getDataAsync()
runs. When the data arrives, thenAccept
is called automatically.
Async/Await: Non-Blocking, But Readable
Futures are powerful—but chaining callbacks can quickly become messy. That’s where async/await
shines. It allows developers to write non-blocking code in a synchronous style—clean, readable, and maintainable.
Here’s a simple Python example:
async def fetch_data():
response = await http_get("https://example.com") print(response)
What’s happening here:
await
tells Python: "Pause here, let other things run while this completes."The function is non-blocking, even though it looks synchronous.
This makes it easier to follow control flow, handle errors, and write more intuitive async code.
How It Works Under the Hood
While it looks simple, behind the scenes async/await uses:
Event loops (like
libuv
in Node.js orasyncio
in Python)Coroutines that can pause and resume
Promises/Futures to track completion
The event loop watches for completed tasks and resumes your function when it’s ready. This allows concurrent execution without multithreading.
Language Support at a Glance
Language | Feature | Support |
---|---|---|
JavaScript |
| Native |
Python |
| 3.5+ |
Rust |
| Stable (via |
Java |
| Supported |
Go | Goroutines (not async/await) | Built-in concurrency model |
When to Use Async/Await
Great for:
API calls
File or network I/O
Server-side request handling
Parallelizing tasks efficiently
Not great for:
CPU-bound tasks (use threads or background workers instead)
Simple, linear scripts
Code that doesn’t require high concurrency
Common Mistakes to Avoid
Mixing sync and async improperly
Example: callingawait
in a non-async functionBlocking the event loop
Example: doing heavy computation inside an async function without offloading itError handling
Usetry/await
or.catch()
wisely—async code often fails silently if not handled
Final Thought
Async/await and Futures allow you to build fast, responsive apps without drowning in threads or callbacks. As systems scale and demands increase, non-blocking code isn’t just a bonus—it’s a necessity.
The good news? You don’t need to sacrifice clarity to gain concurrency. With async/await, performance and readability can go hand-in-hand.
Until next time,
— Team Nullpointer Club
Reply