Using Typescript - how to monitor the completion of an asynchronous function without utilizing the await keyword

In the scenario provided, we have a situation where functionThatCannotBeAsync() cannot be async due to system-wise reasons. However, it still needs to call someAsyncStuff(), wait for it to finish, and then return with its result.

An attempt has been made to resolve this by using a combination of callbacks and a while loop:

async someAsyncStuff(res, callback) {
    let result = await stuffToDo()
    
    res.result = result
    callback()
    return result
}

functionThatCannotBeAsync() {
   let done = false
   let result = {result: ""}

   someAsyncStuff(result, () => { done = true })

   while(!done) {}
   return result.result
}

The expectation was that the while loop in functionThatCannotBeAsync() would wait until the asynchronous operation is complete, at which point 'done' would become true and the desired value would be returned. However, in reality, the while loop continues indefinitely.

If anyone could provide insight into why this behavior is occurring and suggest an alternative approach (aside from using async/await), it would be greatly appreciated.

Thank you in advance

Answer №1

One way to return a Promise implicitly is by using the following method:

/* This code snippet demonstrates how you can create a function that fetches data from an endpoint and returns a promise without utilizing `async`/`await`
*/
function functionNoAsync(url) {

  return new Promise(resolve => {
     fetch(url)
        .then(response => response.json())
        .then(jsonResponse => resolve(jsonResponse));
  })
}

const exampleFunction = async () => {
 const apiData = await functionNoAsync("http://api.example.com/data");
 console.log("Data received: ", apiData);
}
exampleFunction();

Answer №2

UPDATE: Upon reflection, it appears that my previous approach was influenced by a habit of using await at the top level. It's important to understand why the while loop failed to function as intended. For more information on why using while can be problematic for the event loop and fail to execute properly, refer to this explanation:

The main issue with the while() loop is that it continues running until the flag changes its value. While this loop is active, it blocks the event loop. This means that even though there's a setTimeout() scheduled to fire in 1 second, it cannot trigger its callback function until the interpreter returns control to the event loop.

In essence, the done value never gets updated because the loop is effectively trapping the program inside it, leading to an infinite loop scenario.

To achieve a similar syntax as desired, utilizing a callback is recommended. It's essential to explicitly handle the result within the functionThatCannotBeAsync.

functionThatCannotBeAsync() {
  const awaiting = someAsyncStuff() //This is a promise
  awaiting.then((value) => {
    //perform actions with the value,
    return value
  })
}

It's worth noting that this code does not block the thread!

//Some other part of the code
console.log(typeof functionThatCannotBeAsync() === undefined)
//true <- Not the expected outcome!

This scenario is undesirable 99% of the time.

Instead, opting for a callback approach, where a callback function is passed as a parameter, is more favorable. The type of value corresponds to what is anticipated from the await function. This pattern aligns with the purpose of async/await, aiming to mitigate issues like callback hell. It signifies that any dependent code relying on the awaited value must exist within the callback function in order to avoid falling into a callback hell situation, provided this function is the only one unable to be asynchronous.

functionThatCannotBeAsync(callback: (value: any) => void) {
  const awaiting = someAsyncStuff()
  awaiting.then((value) => {
    const newValue = value+'bar'
    callback(newValue)
  })
}

Subsequently, in another section of the code:

functionThatCannotBeAsync((value) => {
  console.log("I am code dependent on value!")
  //perform actions based on the value
})
console.log("I am code not dependent on value!")
// logs:
// 'I am code not dependent on value!'
// 'I am code dependent on value!'

An alternative method closely resembling JayCodist's suggestion involves manipulating the result within the functionThatCannotBeAsync, subsequently returning a promise elsewhere to enable the use of await in that location.

function functionThatCannotBeAsyncPromise() {
    const awaiting = someAsyncStuff() //This is a promise
    const promise = new Promise((resolve, reject) => {
      awaiting.then((value: string) => {
        const newValue = value+'bar'
        resolve(newValue)
      }).catch((reason) => {
        throw new Error(reason)
        //alternatively, we could use reject
        //reject(reason)
      })
    })
    return promise
}
//...
//Elsewhere in the code
const value = await functionThatCannotBeAsync();

Here are functional examples on TS playground

For further reading:

The original response is retained below for historical purposes or reference...

An alternative technique involves utilizing an immediately invoked anonymous expression, known as IIFE, to convert an asynchronous function into a synchronous one.

With an async IIFE, you can employ await and for-await even in older browser environments and JavaScript setups lacking support for top-level await:

This assumes no intermediate operations are necessary between calling the IIFE and receiving its output

functionThatCannotBeAsync() {
   (async () => await someAsyncStuff())()
   // wait for the operation above to complete
   // return with the result
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to get jQuery scrollTo() function to work within Angular 4

I have encountered an issue while using a library called ng2-pdf-viewer. The default way to stick to a page in the PDF document was not working as expected. To overcome this, I utilized jQuery's scrollTo() method to navigate to the specific .page clas ...

The specified property ID is not found in the User type

I recently started using TypeScript and decided to practice by implementing user authentication with Passport.js in a small application. Challenge The issue I'm facing is related to instructing Passport.js to store the id property of the user in the ...

Managing HTTP requests with errors within a forEach loop in Angular 9

I am currently coding a script that iterates through an array to make HTTP requests. Most of these requests are directed towards non-existent resources, but I do not have information on which ones specifically. Here is the code snippet I am using: ...

How do I increment my variable with each iteration in a forEach loop in TypeScript?

I'm working on a function with a forEach loop and I need to keep track of how many times the loop is executed. Can anyone suggest a way to tweak my logic to achieve this? Below is what I have tried so far: createUIListElements(){ xml2js.parseStri ...

turning off next.js server side rendering in order to avoid potential window is undefined issues

I am currently managing a private NPM package that is utilized in my Next.js project, both of which are React and Typescript based. Recently, I integrated a graph feature into the NPM package and encountered an issue where any reference to window within t ...

Can someone assist me with running queries on the MongoDB collection using Node.js?

In my mongodb collection called "jobs," I have a document format that needs to display all documents matching my query. { "_id": { "$oid": "60a79952e8728be1609f3651" }, "title": "Full Stack Java Develo ...

The ng-model used within an *ngFor loop is not displaying the correct value

I am working with a JSON file in my Angular2 App. The specific JSON object I am referring to is named tempPromotion and I am trying to access the data within ['results'] like this: tempPromotion['response_payload']['ruleset_list ...

Overhauling JSON Data Output in Angular Version 2 and beyond

Currently, I am dealing with a complex web API JSON response that contains nested data. I would like to simplify the structure by extracting only the necessary information. How can I achieve this using Angular 2+/Typescript? I would greatly appreciate an ...

What is the best way to integrate ag-grid with Observable in Angular 2?

After conducting extensive research on the Internet, I am still struggling to connect the pieces. My angular2 application utilizes an Observable data source from HTTP and I am attempting to integrate ag-grid. However, all I see is a loading screen instead ...

Error in VueJS/Typescript: Module 'my-module' or its type declarations are not found

Hey fellow developers! I'm currently working on a Vue2 setup with Nuxt and Typescript. I'm facing an issue while trying to install the awesome vue-slick-carousel module via yarn. When attempting to import the module in my component, Typescript th ...

Unit Testing AngularJS Configuration in TypeScript with Jasmine

I'm in the process of Unit Testing the configuration of a newly developed AngularJS component. Our application uses ui-router for handling routing. While we had no issues testing components written in plain Javascript, we are encountering difficulties ...

TypeScript does not have access to the array prototype

Despite searching through various stack overflow responses, I haven't been able to resolve my error. I've attempted the following: A B Below is my TypeScript code snippet: interface Array<T> { asyncForEach(callback: CallableFunction): v ...

React Hook: Child Component's onComplete Callback Cannot Call Parent Component's Dispatch

I've attempted multiple solutions to address this issue, but none have proven successful. In my scenario, a third-party library makes an asynchronous call to load content for rendering in the DOM. To integrate this functionality, I have a component ...

The occurrence of a loading error arises when attempting to load the second component, displaying the message 'The template instructed for component SidebarComponent is

My journey with Angular has just begun, and I decided to challenge myself by creating a simplistic dashboard. In order to achieve this, I developed two components called DashboardComponent and SidebarComponent. The DashboardComponent loads smoothly witho ...

Leveraging keyof and Pick from a single source list for type definitions

In order to streamline the process, I want to define the necessary properties in a single list[], and then use that as the template for both types I am utilizing. Currently, I have to manually input them in two separate locations. By employing keyof, I ca ...

NextJS is currently unable to identify and interpret TypeScript files

I am looking to build my website using TypeScript instead of JavaScript. I followed the NextJS official guide for installing TS from scratch, but when I execute npm run dev, a 404 Error page greets me. Okay, below is my tsconfig.json: { "compilerOption ...

Mastering the art of iterating through nested for loops on table rows with Angular

I want to iterate through a for loop to display response data in table rows, and I need the data values in array format. Can you please guide me on how to achieve this with the code provided below? HTML file <div class="row"> <f ...

What is the process for adjusting the color of axes in vue-chartjs?

Seeking help on how to adjust the color of the axis in my graph. Has anyone encountered a similar issue before? The chart I'm working with resembles the one shown in the image. Not sure if this issue is related to it being a time graph. Below is the V ...

Having trouble retrieving values from a feature file in a Typescript implementation with the Cucumber Framework

Having trouble accessing values from a feature file in Typescript while using the Cucumber Framework tool Protractor. How do I retrieve these Example values in my typescript method within the When block? Here is the code for the Feature file: Feature: Na ...

After updating the state in a Reducer with Redux Toolkit, make sure to utilize a

Issue: Seeking efficient code writing methods. Here is a detailed example of my Redux Toolkit slice below: import { createSlice } from '@reduxjs/toolkit'; import { setCookie } from '../../utils/storageHandler'; const initialState = { ...