Facebook Pixel

2723. Add Two Promises

Problem Description

This problem asks you to create a function that takes two promises as input, where each promise will resolve to a number. Your task is to return a new promise that resolves to the sum of the two numbers from the input promises.

The function signature is:

  • Input: Two promises (promise1 and promise2), each resolving to a number
  • Output: A single promise that resolves to the sum of the two numbers

For example, if promise1 resolves to 2 and promise2 resolves to 2, the returned promise should resolve to 4.

The solution uses async/await syntax to handle the asynchronous operations. By using await on each promise, the function waits for both promises to resolve and then adds their resolved values together. The async function automatically wraps the result in a promise, which is exactly what the problem requires.

The key insight is that you need to wait for both promises to complete before you can add their values, and the result itself must be wrapped in a promise to match the expected return type Promise<number>.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When working with promises that resolve to values we want to combine, we need to think about the asynchronous nature of the operations. Since both promises will eventually produce numbers, and we want to add them, we need to wait for both values to be available before performing the addition.

The natural approach is to use async/await because it allows us to write asynchronous code that looks and behaves like synchronous code. When we mark a function as async, it automatically returns a promise, which satisfies our requirement of returning Promise<number>.

Inside the function, we use await on each promise to extract their resolved values. The expression (await promise1) + (await promise2) first waits for promise1 to resolve and gets its value, then waits for promise2 to resolve and gets its value, and finally adds them together. The beauty of this approach is its simplicity - we're essentially telling JavaScript to "wait for both values, then add them."

The alternative would be to use .then() chaining or Promise.all(), but the async/await approach is the most straightforward and readable. Since the function is marked as async, the sum is automatically wrapped in a promise when returned, giving us exactly what we need without any extra promise construction.

Solution Approach

The implementation uses the async/await pattern to handle the asynchronous operations cleanly:

async function addTwoPromises(
    promise1: Promise<number>,
    promise2: Promise<number>,
): Promise<number> {
    return (await promise1) + (await promise2);
}

Let's break down how this works step by step:

  1. Function Declaration: The function is declared with the async keyword, which means it will automatically return a promise. This satisfies our return type requirement of Promise<number>.

  2. Awaiting the First Promise: When we write await promise1, the execution pauses until promise1 resolves. Once it resolves, we get the actual number value (not the promise object).

  3. Awaiting the Second Promise: Similarly, await promise2 pauses execution until promise2 resolves and gives us its number value.

  4. Addition Operation: Once both promises have resolved, we have two number values that can be added together using the standard + operator.

  5. Automatic Promise Wrapping: Since the function is async, the result of the addition is automatically wrapped in a promise before being returned.

The execution flow can be visualized as:

  • Start with two Promise objects
  • Extract the number from promise1 using await
  • Extract the number from promise2 using await
  • Add the two numbers together
  • Return the sum wrapped in a Promise

This approach handles the promises sequentially (promise1 first, then promise2), but both promises can be executing concurrently in the background. The function simply waits for both to complete before performing the addition.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to understand how the solution works:

Example Input:

  • promise1 = new Promise(resolve => setTimeout(() => resolve(10), 50))
  • promise2 = new Promise(resolve => setTimeout(() => resolve(5), 30))

Step-by-step execution:

  1. Function Call: We call addTwoPromises(promise1, promise2)

  2. Initial State:

    • Both promises start executing immediately when created
    • promise1 will resolve to 10 after 50ms
    • promise2 will resolve to 5 after 30ms
  3. First Await (await promise1):

    • The function encounters await promise1 and pauses
    • Even though promise2 resolves first (at 30ms), we're waiting for promise1
    • After 50ms, promise1 resolves to 10
    • The value 10 is extracted
  4. Second Await (await promise2):

    • The function encounters await promise2
    • Since promise2 has already resolved (it finished at 30ms), we immediately get the value 5
    • No additional waiting is needed
  5. Addition:

    • Now we have both values: 10 and 5
    • The addition is performed: 10 + 5 = 15
  6. Return:

    • The async function automatically wraps 15 in a promise
    • Returns Promise<15> which will resolve to 15

Timeline visualization:

Time:     0ms    30ms    50ms
promise1: [-------|-------✓] resolves to 10
promise2: [-------✓] resolves to 5
Function:         waits→ gets both values → returns Promise<15>

The key insight is that even though the promises resolve at different times, the function waits for both to complete before performing the addition, and the result is automatically wrapped in a promise.

Solution Implementation

1import asyncio
2from typing import Awaitable
3
4async def addTwoPromises(
5    promise1: Awaitable[int],
6    promise2: Awaitable[int]
7) -> int:
8    """
9    Adds the resolved values of two number promises together.
10  
11    Args:
12        promise1: First promise that resolves to a number
13        promise2: Second promise that resolves to a number
14  
15    Returns:
16        A promise that resolves to the sum of both resolved values
17    """
18    # Await both promises to resolve and return their sum
19    return (await promise1) + (await promise2)
20
21
22# Example usage:
23# async def main():
24#     result = await addTwoPromises(
25#         asyncio.create_task(asyncio.coroutine(lambda: 2)()),
26#         asyncio.create_task(asyncio.coroutine(lambda: 2)())
27#     )
28#     print(result)  # Output: 4
29#
30# asyncio.run(main())
31
1import java.util.concurrent.CompletableFuture;
2
3/**
4 * Adds the resolved values of two number promises together
5 * @param promise1 - First promise that resolves to an integer
6 * @param promise2 - Second promise that resolves to an integer
7 * @return A CompletableFuture that resolves to the sum of both resolved values
8 */
9public class PromiseAdder {
10  
11    public static CompletableFuture<Integer> addTwoPromises(
12            CompletableFuture<Integer> promise1,
13            CompletableFuture<Integer> promise2) {
14      
15        // Combine both futures and apply the sum operation when both complete
16        return promise1.thenCombine(promise2, (num1, num2) -> num1 + num2);
17    }
18  
19    /**
20     * Example usage:
21     * public static void main(String[] args) {
22     *     CompletableFuture<Integer> result = addTwoPromises(
23     *         CompletableFuture.completedFuture(2),
24     *         CompletableFuture.completedFuture(2)
25     *     );
26     *     
27     *     // Print the result when available
28     *     result.thenAccept(System.out::println); // Output: 4
29     * }
30     */
31}
32
1#include <future>
2#include <iostream>
3
4/**
5 * Adds the resolved values of two number promises (futures) together
6 * @param promise1 - First future that resolves to an integer
7 * @param promise2 - Second future that resolves to an integer
8 * @returns A future that resolves to the sum of both resolved values
9 */
10std::future<int> addTwoPromises(
11    std::future<int> promise1,
12    std::future<int> promise2) {
13    // Create an async task that waits for both futures and returns their sum
14    return std::async(std::launch::async, [](std::future<int> p1, std::future<int> p2) {
15        // Get the values from both futures (blocking until they're ready)
16        int value1 = p1.get();
17        int value2 = p2.get();
18      
19        // Return the sum of both values
20        return value1 + value2;
21    }, std::move(promise1), std::move(promise2));
22}
23
24/**
25 * Example usage:
26 * auto promise1 = std::async(std::launch::async, []() { return 2; });
27 * auto promise2 = std::async(std::launch::async, []() { return 2; });
28 * auto result = addTwoPromises(std::move(promise1), std::move(promise2));
29 * std::cout << result.get() << std::endl; // Output: 4
30 */
31
1/**
2 * Adds the resolved values of two number promises together
3 * @param promise1 - First promise that resolves to a number
4 * @param promise2 - Second promise that resolves to a number
5 * @returns A promise that resolves to the sum of both resolved values
6 */
7async function addTwoPromises(
8    promise1: Promise<number>,
9    promise2: Promise<number>,
10): Promise<number> {
11    // Await both promises to resolve and return their sum
12    return (await promise1) + (await promise2);
13}
14
15/**
16 * Example usage:
17 * addTwoPromises(Promise.resolve(2), Promise.resolve(2))
18 *   .then(console.log); // Output: 4
19 */
20

Time and Space Complexity

Time Complexity: O(max(T1, T2)) where T1 and T2 are the resolution times of promise1 and promise2 respectively.

The function uses await on both promises sequentially. While the syntax appears sequential, JavaScript's event loop and the nature of promises mean that:

  • Both promises start executing when they're created (before being passed to the function)
  • The await operators simply wait for their resolution
  • The actual time taken is determined by whichever promise takes longer to resolve
  • The addition operation itself is O(1)

Space Complexity: O(1)

The function only stores:

  • Two resolved numeric values from the promises
  • The sum of these values
  • No additional data structures or recursive calls are made
  • The space used is constant regardless of the input values

Common Pitfalls

1. Sequential Waiting Instead of Parallel Execution

The current implementation waits for promises sequentially, which can be inefficient:

# Inefficient: waits for promise1 to complete before starting to wait for promise2
return (await promise1) + (await promise2)

If promise1 takes 2 seconds and promise2 takes 3 seconds, the total execution time will be approximately 3 seconds if they run in parallel, but could be up to 5 seconds if truly sequential.

Solution: Use asyncio.gather() to ensure parallel execution:

async def addTwoPromises(
    promise1: Awaitable[int],
    promise2: Awaitable[int]
) -> int:
    # Run both promises in parallel
    result1, result2 = await asyncio.gather(promise1, promise2)
    return result1 + result2

2. Missing Error Handling

If either promise rejects/raises an exception, the function will propagate the error without any handling:

# If promise1 or promise2 raises an exception, it bubbles up uncaught
return (await promise1) + (await promise2)

Solution: Add try-except blocks or use default values:

async def addTwoPromises(
    promise1: Awaitable[int],
    promise2: Awaitable[int]
) -> int:
    try:
        result1, result2 = await asyncio.gather(
            promise1, 
            promise2,
            return_exceptions=False  # Raises first exception encountered
        )
        return result1 + result2
    except Exception as e:
        # Handle error appropriately
        raise ValueError(f"Failed to add promises: {e}")

3. Type Confusion with Coroutines vs Tasks

In Python, there's a distinction between coroutines, tasks, and futures. Passing raw coroutines without properly creating tasks can lead to unexpected behavior:

# Problematic: passing raw coroutines
async def get_number():
    return 2

# Wrong way - coroutine objects aren't automatically scheduled
result = await addTwoPromises(get_number(), get_number())

Solution: Ensure proper task creation:

# Correct way - create tasks explicitly
task1 = asyncio.create_task(get_number())
task2 = asyncio.create_task(get_number())
result = await addTwoPromises(task1, task2)

4. Resource Cleanup on Cancellation

If the parent coroutine is cancelled while waiting, both promises might continue running in the background:

Solution: Use proper cancellation handling:

async def addTwoPromises(
    promise1: Awaitable[int],
    promise2: Awaitable[int]
) -> int:
    try:
        return (await promise1) + (await promise2)
    except asyncio.CancelledError:
        # Ensure both promises are cancelled if one fails
        if hasattr(promise1, 'cancel'):
            promise1.cancel()
        if hasattr(promise2, 'cancel'):
            promise2.cancel()
        raise
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What's the relationship between a tree and a graph?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More