Comparing Async HTTP Requests in Python and JavaScript Using Promises.all

Table of Contents

Introduction

Asynchronous programming is essential for handling I/O-bound operations efficiently, particularly HTTP requests. Both Python and JavaScript provide robust async patterns, though their approaches differ significantly. This document compares the async/await patterns and parallel execution strategies in both languages.

Python Async Patterns

asyncio Basics

Python's asyncio library provides the foundation for asynchronous programming. The key components are:

  • async def: Defines a coroutine function
  • await: Suspends execution until the awaited coroutine completes
  • asyncio.run(): Entry point for running async programs
  • Event loop: Manages and schedules coroutine execution

aiohttp for HTTP Requests

While the standard library's requests module is blocking, aiohttp provides async HTTP capabilities:

import aiohttp
import asyncio

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

asyncio.gather() for Parallel Requests

asyncio.gather() runs multiple coroutines concurrently and waits for all to complete:

import asyncio
import aiohttp

async def fetch_multiple_urls(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        return results

async def main():
    urls = [
        'https://api.github.com/users/github',
        'https://api.github.com/users/python',
        'https://api.github.com/users/microsoft'
    ]
    results = await fetch_multiple_urls(urls)
    for url, result in zip(urls, results):
        print(f"{url}: {len(result)} bytes")

if __name__ == "__main__":
    asyncio.run(main())

JavaScript Async Patterns

Promise Basics

JavaScript Promises represent eventual completion (or failure) of an async operation:

  • new Promise((resolve, reject) => {}): Creates a promise
  • .then(): Handles successful resolution
  • .catch(): Handles errors
  • async/await: Syntactic sugar for working with promises

Fetch API

The Fetch API provides a modern interface for HTTP requests:

async function fetchUrl(url) {
    const response = await fetch(url);
    return await response.text();
}

Promise.all() for Parallel Requests

Promise.all() executes multiple promises concurrently and resolves when all complete:

async function fetchMultipleUrls(urls) {
    const promises = urls.map(url => fetch(url).then(r => r.text()));
    return await Promise.all(promises);
}

async function main() {
    const urls = [
        'https://api.github.com/users/github',
        'https://api.github.com/users/python',
        'https://api.github.com/users/microsoft'
    ];

    const results = await fetchMultipleUrls(urls);
    results.forEach((result, i) => {
        console.log(`${urls[i]}: ${result.length} bytes`);
    });
}

main().catch(console.error);

Comparison Table

Feature Python (asyncio) JavaScript (Promises)
Syntax async/await async/await or .then()
Parallel execution asyncio.gather() Promise.all()
HTTP library aiohttp (3rd party) fetch (built-in)
Error handling try/except try/catch or .catch()
Event loop Explicit (asyncio.run()) Implicit (built-in)
Return on first fail asyncio.wait() + options Promise.race()
Context manager async with Not built-in

Best Practices

Python

  • Always use async with for aiohttp sessions to ensure proper cleanup
  • Use asyncio.gather(return_exceptions=True) to handle partial failures
  • Limit concurrent requests with asyncio.Semaphore to avoid overwhelming servers
  • Consider using asyncio.TaskGroup (Python 3.11+) for better error handling

JavaScript

  • Always handle promise rejections with .catch() or try/catch
  • Use Promise.allSettled() when you need all results regardless of failures
  • Implement timeout mechanisms with Promise.race() and setTimeout
  • Consider request batching for large numbers of concurrent requests

Common to Both

  • Implement retry logic with exponential backoff
  • Set appropriate timeouts for HTTP requests
  • Use connection pooling for better performance
  • Monitor and limit concurrent connections to respect API rate limits

Author: Jason Walsh

j@wal.sh

Last Updated: 2025-12-22 23:08:40

build: 2025-12-29 20:03 | sha: 3c17632