2723. Add Two Promises


Problem Description

In this problem, we are working with asynchronous operations in JavaScript, specifically with promises. A promise is an object representing the eventual completion or failure of an asynchronous operation. We are given two such objects, promise1 and promise2, both of which are expected to resolve with a numerical value. The task is to create and return a new promise that will resolve with the sum of the two numbers provided by promise1 and promise2.

Intuition

The key to solving this problem is understanding how promises work and how to handle the values they resolve with. The async keyword allows us to write asynchronous code in a way that looks synchronous, and the await keyword pauses the execution of the function until a promise is resolved. By using await on both promise1 and promise2, we can get their resolved values. Once both promises have been resolved, we can then simply add these two numerical values together. The sum is then implicitly returned as a resolved promise due to the async function's behavior—any value returned by an async function is automatically wrapped in a Promise.resolve().

So, the "intuition" behind this solution is:

  1. Wait for each promise to resolve using await.
  2. Once both numbers are available, add them together.
  3. The async function will return a promise that resolves with the sum of the two numbers.
Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

How would you design a stack which has a function min that returns the minimum element in the stack, in addition to push and pop? All push, pop, min should have running time O(1).

Solution Approach

The implementation of the solution is straightforward given the understanding of how JavaScript promises and async/await work.

Here's a step-by-step breakdown of the algorithm:

  1. An async function named addTwoPromises is defined, which accepts two parameters: promise1 and promise2. Both parameters are expected to be promises that resolve to numbers.

  2. Inside the function, we use the await keyword before promise1 and promise2. This instructs JavaScript to pause the execution of the function until each promise resolves. The await keyword can only be used within an async function.

  3. When await promise1 is executed, the function execution is paused until promise1 is either fulfilled or rejected. If it's fulfilled, the resolved value (a number) is returned. If promise1 is rejected, an error will be thrown, which can be caught using try...catch blocks.

  4. Similarly, await promise2 pauses the function execution until promise2 resolves, after which it provides the resolved value (a number).

  5. After obtaining both numbers, the function adds these two numbers together with the + operator. The expression (await promise1) + (await promise2) computes the sum.

  6. The resulting sum is then returned from the async function. Because the function is async, this return value is automatically wrapped in a promise. Essentially, return (await promise1) + (await promise2); is equivalent to return Promise.resolve((await promise1) + (await promise2));.

The data structure used here is the built-in JavaScript Promise, which is a proxy for a value that is not necessarily known when the promise is created. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

The pattern used is async/await, which is syntactic sugar over JavaScript Promises, providing a simpler and cleaner way to handle asynchronous operations. It allows for writing promise-based code as if it were synchronous, but without blocking the main thread.

This solution leverages the concurrency nature of promises to potentially execute both promise1 and promise2 at the same time, reducing the overall waiting time for both promises to resolve.

Therefore, the solution is concise, clear, and leverages modern JavaScript features to work with asynchronous operations effectively.

Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

What is the worst case running time for finding an element in a binary tree (not necessarily binary search tree) of size n?

Example Walkthrough

To illustrate the solution approach, let's walk through a small example using two sample promises that resolve to numerical values.

Suppose we have two promises:

1const promise1 = new Promise((resolve, reject) => {
2    setTimeout(() => resolve(10), 1000); // promise1 resolves with 10 after 1 second
3});
4
5const promise2 = new Promise((resolve, reject) => {
6    setTimeout(() => resolve(20), 500); // promise2 resolves with 20 after 0.5 seconds
7});

These promises, when executed, will resolve with the numbers 10 and 20, respectively, after their set timeouts.

Let's go through the steps of the solution with these promises:

  1. We define an async function addTwoPromises that takes promise1 and promise2 as parameters.
1async function addTwoPromises(promise1, promise2) {
2    // The function body will be implemented according to the steps.
3}
  1. We await both promise1 and promise2 using the await keyword inside the async function. This way we can get their resolved values:
1async function addTwoPromises(promise1, promise2) {
2    const value1 = await promise1; // Execution pauses here until promise1 resolves.
3    const value2 = await promise2; // Execution pauses here until promise2 resolves.
4    // The rest of the function...
5}
  1. After both promises resolve, value1 has the value 10, and value2 has the value 20.

  2. We then add value1 and value2 and return the result:

1async function addTwoPromises(promise1, promise2) {
2    const value1 = await promise1;
3    const value2 = await promise2;
4    return value1 + value2; // The function will return a Promise that resolves to 30
5}
  1. Since addTwoPromises is an async function, the returned result will be wrapped in a promise. Therefore, calling addTwoPromises(promise1, promise2) will return a promise that resolves to the sum of the two values, which is 30 in this case.

  2. If we want to use the result of the addTwoPromises function, we can do so by attaching a .then method or using an await within another async function:

1addTwoPromises(promise1, promise2).then(sum => {
2    console.log(sum); // This will log 30 to the console once the promise resolves
3});

or,

1async function displayResult() {
2    const result = await addTwoPromises(promise1, promise2);
3    console.log(result); // This will also log 30 to the console
4}

And that concludes the example walkthrough of how to use the solution approach to add two numbers provided by promises asynchronously.

Solution Implementation

1import asyncio
2
3# Function that adds the values resolved from two futures.
4# Takes two futures that resolve to numbers as parameters.
5async def add_two_promises(future1, future2):
6    """
7    This coroutine waits for two futures to resolve and adds their results.
8
9    :param future1: A future (async result) that resolves to a number.
10    :param future2: A future (async result) that resolves to a number.
11    :return: The sum of the two numbers when both futures have resolved.
12    """
13    # Await the resolution of the first future and store the resulting value.
14    value1 = await future1
15  
16    # Await the resolution of the second future and store the resulting value.
17    value2 = await future2
18  
19    # Return the sum of the two values.
20    return value1 + value2
21
22# Example usage of the add_two_promises coroutine:
23# - Resolves two futures, each with the value 2, and logs the sum, which is 4.
24async def main():
25    result = await add_two_promises(asyncio.Future(), asyncio.Future())
26    print(result)  # Expected output: 4
27
28# Initialize two futures and set their results to 2.
29future1 = asyncio.ensure_future(asyncio.sleep(0, result=2))
30future2 = asyncio.ensure_future(asyncio.sleep(0, result=2))
31
32# Run the main coroutine that utilizes the add_two_promises coroutine.
33asyncio.run(main())
34
1import java.util.concurrent.CompletableFuture;
2import java.util.concurrent.ExecutionException;
3
4// Class containing the method to add values from two CompletableFutures
5public class FutureAdder {
6
7    // Function that adds the values from two CompletableFutures.
8    // Takes two CompletableFutures that complete with numbers as parameters.
9    public static CompletableFuture<Integer> addTwoFutures(
10        CompletableFuture<Integer> future1,
11        CompletableFuture<Integer> future2) {
12
13        // Combine both futures to sum the resolved numbers once both are completed
14        return future1.thenCombine(future2, Integer::sum);
15    }
16
17    // Example usage of the addTwoFutures method
18    public static void main(String[] args) {
19        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> 2);
20        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> 2);
21
22        // Compute the sum of both future's results
23        CompletableFuture<Integer> sumFuture = addTwoFutures(completableFuture1, completableFuture2);
24
25        // Log the result once computation is complete
26        sumFuture.thenAccept(System.out::println) // Expected output: 4
27                 .exceptionally(ex -> { // In case of an exception, cope with it here
28                     System.out.println("An error occurred: " + ex.getMessage());
29                     return null;
30                 });
31        // To ensure that the application does not terminat before completing the future computation
32        // Handle with care as it may cause the application to hang if futures don't complete
33        try {
34            sumFuture.get();
35        } catch (InterruptedException | ExecutionException ex) {
36            ex.printStackTrace();
37        }
38    }
39}
40
1#include <iostream>
2#include <future>
3#include <functional>
4
5// Function that adds the values obtained from two futures.
6// Takes two futures that will provide numbers as parameters.
7std::future<int> addTwoFutures(std::future<int>&& future1, std::future<int>&& future2) {
8    // Create a new std::promise<int> that will eventually hold the result
9    std::promise<int> result_promise;
10  
11    // Get the std::future<int> associated with the result_promise
12    std::future<int> result_future = result_promise.get_future();
13  
14    // Lambda that processes the addition of two future values
15    auto compute = [](std::future<int>&& future1, std::future<int>&& future2, std::promise<int> result_promise) mutable {
16        // Wait for the first future to be ready and get its value
17        int value1 = future1.get();
18
19        // Wait for the second future to be ready and get its value
20        int value2 = future2.get();
21
22        // Set the promise's value to the sum of the two obtained values
23        result_promise.set_value(value1 + value2);
24    };
25  
26    // Start asynchronous execution
27    std::async(std::launch::async, compute, std::move(future1), std::move(future2), std::move(result_promise));
28  
29    // Return the future that will provide the sum
30    return result_future;
31}
32
33// Example usage of the addTwoFutures function
34// - Resolves two futures, each with the value 2, and logs the sum, which is 4.
35int main() {
36    // Create two promises
37    std::promise<int> promise1;
38    std::promise<int> promise2;
39
40    // Set values to the promises
41    promise1.set_value(2);
42    promise2.set_value(2);
43
44    // Get futures from promises
45    std::future<int> future1 = promise1.get_future();
46    std::future<int> future2 = promise2.get_future();
47
48    // Call addTwoFutures with the futures we got from the promises
49    std::future<int> result = addTwoFutures(std::move(future1), std::move(future2));
50
51    // Wait for the result future to be ready and get its value, then print
52    std::cout << "Expected output: " << result.get() << std::endl; // Expected output: 4
53
54    return 0;
55}
56
1// Function that adds the values resolved from two promises.
2// Takes two promises that resolve to numbers as parameters.
3async function addTwoPromises(
4    promise1: Promise<number>,
5    promise2: Promise<number>,
6): Promise<number> {
7    // Await the resolution of the first promise and store the resulting value.
8    const value1 = await promise1;
9  
10    // Await the resolution of the second promise and store the resulting value.
11    const value2 = await promise2;
12  
13    // Return the sum of the two values.
14    return value1 + value2;
15}
16
17// Example usage of the addTwoPromises function:
18// - Resolves two promises, each with the value 2, and logs the sum, which is 4.
19addTwoPromises(Promise.resolve(2), Promise.resolve(2))
20    .then(console.log); // Expected output: 4
21
Not Sure What to Study? Take the 2-min Quiz:

How many ways can you arrange the three letters A, B and C?

Time and Space Complexity

Time Complexity

The time complexity of the function addTwoPromises largely depends on how promise1 and promise2 resolve. However, since it is awaiting both promises one after the other, it will be at least as long as the longest time taken for either of the promises to resolve. If the promises do not depend on each other and could resolve in parallel, this sequential waiting increases the total time unnecessarily. Therefore, if T1 is the time taken for promise1 to resolve and T2 is the time taken for promise2 to resolve, the time complexity would be O(T1 + T2) where T1 and T2 are the respective completion times for each promise. If promise1 and promise2 were to be awaited in parallel, the time complexity could be improved to O(max(T1, T2)).

Space Complexity

The space complexity of the function addTwoPromises itself is O(1), as it only needs the space for two number variables when the promises resolve, and one number for the return value. There is no additional space being used that scales with the size of the input.

Fast Track Your Learning with Our Quick Skills Quiz:

Suppose k is a very large integer(2^64). Which of the following is the largest as n grows to infinity?


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫