Step 13 – Asynchronous programming with TypeScript

image 2

Play Store Application link – Java to TypeScript in 14 Steps – App on Google Play

Asynchronous programming is crucial for building scalable and responsive applications. It allows code to run without blocking the main thread, improving performance and user experience. In this step, we’ll explore how to handle asynchronous operations in TypeScript and compare these approaches with Java.

Callbacks

TypeScript Example:

Callbacks are one of the simplest methods for handling asynchronous operations. A callback is a function passed as an argument to another function, which is invoked once the asynchronous task completes.

function fetchData(callback: (data: string) => void) {
  setTimeout(() => {
    callback("Some data");
  }, 1000);
}

fetchData((data) => {
  console.log(data);
});

Java Comparison:

In Java, callbacks are often implemented using interfaces. You define an interface with a method that the callback function will implement.

// Callback interface
interface Callback {
    void onDataReceived(String data);
}

// Class that performs an asynchronous operation
class DataFetcher {
    void fetchData(Callback callback) {
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                callback.onDataReceived("Some data");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        DataFetcher fetcher = new DataFetcher();
        fetcher.fetchData(data -> System.out.println(data));
    }
}

Promises

TypeScript Example:

Promises provide a more structured way to handle asynchronous operations. They represent a value that may be available now, in the future, or never.

function fetchData(): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Some data");
    }, 1000);
  });
}

fetchData()
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.error(error);
  });

Java Comparison:

Java uses the CompletableFuture class to represent a future result of an asynchronous computation. It allows you to chain computations and handle results or errors.

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                return "Some data";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).thenAccept(data -> System.out.println(data))
          .exceptionally(error -> {
              System.err.println(error);
              return null;
          });
    }
}

Async/Await

TypeScript Example:

Async/await provides a more readable and straightforward way to work with Promises, making asynchronous code look like synchronous code.

async function fetchData(): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Some data");
    }, 1000);
  });
}

async function main() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

main();

Java Comparison:

In Java, while there’s no direct equivalent to async/await, you can achieve similar results using CompletableFuture combined with lambda expressions.

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                return "Some data";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        future.thenAccept(data -> System.out.println(data))
              .exceptionally(error -> {
                  System.err.println(error);
                  return null;
              });
    }
}

Conclusion

Asynchronous programming is essential for modern applications, and both TypeScript and Java provide robust mechanisms to handle it. TypeScript uses callbacks, Promises, and async/await to manage asynchronous operations efficiently. Java offers interfaces for callbacks and CompletableFuture for Promises, providing a way to handle asynchronous results and exceptions.

By understanding these concepts and their implementations in both languages, you can write scalable and responsive code that leverages asynchronous processing effectively.


Leave a Reply

Your email address will not be published. Required fields are marked *