How can you determine if an asynchronous function is actively running at the beginning of the "code"?

I am currently working on a project that requires access to a global context which can identify the function running at any given moment. While this task is straightforward with single-threaded synchronous functions that run from start to finish, async functions present a challenge as they can move around the program multiple times before completion.

let currentlyRunningProgram: string[] = [];
function run(id: string, cb: () => any) {
  currentlyRunningProgram.push(id);
  cb()
  currentlyRunningProgram.shift();
}

// works with synchronous tasks
run("foo", () => {
  run("bar", () => console.log("bar should be running"));
  console.log("now foo is running");
});

// Can we do the same with asynchronous functions?
run("qux", async () => {
  // Async functions don't execute immediately...
  await somePromise();
  // and have frequent starts and stops
});

Is it feasible to monitor an asynchronous function to determine if it is actively running or waiting for something?


EDIT: It appears that there is a concept similar to this called Zone.js, commonly used by Angular.

  • Something like async_hooks for the browser?

EDIT: As per @Bergi's recommendation, the term "stack" has been replaced with "program" for better clarity

Answer №1

Believe it or not, the angular developers have actually achieved this feat, although it comes at a hefty price tag of 5.41Mb!!

https://www.npmjs.com/package/zone.js

This information was sourced from a similar query on Stack Overflow: Something like async_hooks for the browser?

To provide some unique insights, I will address the core question here:

Absolutely, you are able to track when an async function begins and ends. For more details, check out the project code

Specifically, it seems that this particular file handles the poly-filling of promises. It may take some time to confirm if this is where the magic truly happens. With some dedication, we may be able to simplify this process into something more accessible, without the need for a whopping 5.41 Mb.

Answer №2

Achieving this is definitely feasible.

By utilizing a running context, such as a mutex, inspired by Edgar W. Djiskistra, stack queues, Promise states, and the Promise.all executor, you can effectively monitor the presence of an active function within the program. It will be necessary to incorporate a garbage collector to maintain the cleanliness of the mutex list, along with employing a timer (setTimeout) to confirm the cleanliness of the context. Once the context is deemed clean, a callback-like function, such as process.exit(0), can be invoked to conclude your program. In this scenario, "context" pertains to the entire sequence of execution in the program.

Converting the function into a promise and utilizing an .then callback to eliminate/clear the stack of the mutex post-execution of the function's content, coupled with a try/catch block to manage, catch, or log errors, adds further control to the overall program.

The introduction of setTimeout facilitates the formation of a state machine when combined with the mutex/lock mechanism, while also introducing a memory leak that demands vigilant monitoring of the timer to release the memory allocated by each function.

This management is achieved through nested try/catch blocks. The utilization of setInterval in this context introduces a memory leak that may lead to a buffer overflow.

The timer serves as the termination point for the program. By keeping track of whether a function is currently running and registering every function executing synchronously using await and mutex, the program's operation becomes more organized.

Operating the program/interpreter synchronously helps prevent memory leaks and race conditions, ensuring smooth functionality. A snippet of code illustrating these concepts is provided below.


const async run (fn) => {
  // Function execution context stack length
  const functionContextExecutionStackLength = functionExecutionStackLength + 1
  
  // Check Mutex Stack Queue
  const checkMutexStackQueue = () => {
    if (mutexStack[0] instanceof Promise) {
      if (mutex[0].state == "fullfiled") {
        mutexStack = mutexStack.split(1, mutexStack.length)
        runner.clear()
        runner()
      }
    }

    if (mutexStack.length == 0) process.exit(0)
  }

  // Clearing function Exection Context
  const stackCleaner = setTimeout(1000, (err, callback) => {
    if (functionContextExecutionStackLength == 10) {
      runner.clear()
    }
  })

  stackCleaner = stackCleaner()

  // Avoiding memory leak on function execution context
  if (functionContextExecutionStackLength == 10) {
    stackCleaner.clear()
    stackCleaner()
  }

  // The Runner
  const runner = setTimeout(1, async (err, callback) => {
    // Run syncronous 
    const append = (fn) => mutex.append(util.promisfy(fn)
      .then(appendFunctionExectionContextTimes)
      .then(checkMutexStackQueue))

    // Transform into promise with callback
    const fn1 = () => util.promify(fn)
    const fn2 = () => util.promisfy(append)

    const orderOfExecution = [fn1, fn2, fn]

    // A for await version can be considered
    for (let i = 0; i < orderOfExecution.length; i++) {
      if (orderOfExecution.length == index) {
        orderOfExecution[orderOfExecution.length]()
      } else {
        try {
          orderOfExecution[i]()
        } catch (err) {
          throw err
          console.error(err)
        }
      }
    }
  }
}

(() => run())(fn)

In the aforementioned code, we approach the asynchronous nature of JavaScript diligently, avoiding it when unnecessary and embracing it when beneficial.


Note:

  • Some variables have been omitted for demonstration purposes.
  • At times, you may notice variable context switching and calls before execution due to the characteristics of ES modules reading and interpreting all contents later on.

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

jQuery DatePicker Not Displaying Calendar

I've been attempting to implement a date picker in jQuery. I've included the necessary code within the head tag: <link rel="stylesheet" type="text/css" media="screen" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jqu ...

Transferring a PHP array to JavaScript using AJAX

I have spent time searching for answers to my issue with no success. My PHP file includes the following array: $data = ['logged' => $_SESSION['loggedin'], 'sessName' => $_SESSION['name']]; echo json_encode($dat ...

A guide to accessing the currently hovered element on a Line Chart with Recharts

Just diving into this community and also new to ReactJS :( https://i.stack.imgur.com/k682Z.png I'm looking to create a tooltip that displays data only when hovering over the value 1 line. Unfortunately, the current tooltip is not behaving as expecte ...

Enhance the MUI palette by incorporating TypeScript, allowing for seamless indexing through the palette

When utilizing the Material UI Palette with Typescript, I am encountering a significant issue due to limited documentation on MUI v5.0 in this area. Deep understanding of typescript is also required. The objective is to iterate through the palette and vir ...

Prioritize loading iframes before other webpage content

My webpage includes an iframe, but the content within it only loads after all other content on the page has loaded. Is there a way to prioritize loading the iframe content before the rest of the page? Thanks! ...

Struggling to make Radio Buttons function properly within an ng-repeat loop while using font-awesome icons as labels

I am facing some difficulties with implementing Font Awesome icons for radio buttons in an AngularJS ng-repeat. I have tried different solutions that involve using $parent within the ng-repeat, but none of them have worked for me so far. It is important fo ...

The jQuery function fail() is triggered when the Flickr API fails to return data

I have been troubleshooting an issue with the Flickr Api url. It appears to return data correctly for my images when accessed directly, but I am encountering difficulties when trying to include it in $.ajax() and $.getJson(). The data does not load and the ...

A guide on scheduling automatic data insertion in mongoose.js

I'm working on a website with Node.js and Mongoose, and I could use some guidance on how to automatically insert data into Mongoose with Node.js at specific times. For example, at the end of each month, I want my current data to be stored in the Mongo ...

When the wireframe property is set to true, the react-three-renderer will only render geometry using the <meshBasicMaterial>

I am new to using the three.js library along with react-three-renderer. I have encountered a problem where only geometry renders when the wireframe property is set to true. If the wireframe property is false (which is the default setting), I expect the mes ...

In Angular 2, transferring data from a parent route to a child route

I have set up a route named "home" with three child routes: documents, mail, and trash. Within the home route component, there is a variable called 'user'. While I am familiar with various methods of passing information between parent and child c ...

Creating Original Tweets using Javascript without Repeating Images

I'm developing a Twitter bot using the Twit NPM package and need assistance on how to avoid posting duplicate images when uploading images to Twitter. The current image_path variable is responsible for scanning through my image directory, but I want ...

Managing dependencies with Yarn or npm

While experimenting with remix and mui v5, I encountered some issues. When using npm and running npm run dev, I received the following error: Error: Directory import '.../playground/remix-mui-dev/node_modules/@mui/material/styles' is not supporte ...

Resource Jump.js could not be loaded

Although I am still new to NPM, I have mostly built websites without using it. Recently, I decided to implement smooth scroll using Jump.js. Initially, everything seemed to work well when I used the live server extension in VScode. However, once I uploade ...

JavaScript: When utilizing 'this' along with nextSibling, encountering the issue of undefined not being an object

When I run a function on the click of a button in my HTML, I want to retrieve the innerHTML value of the sibling element that was clicked. However, I keep receiving the error message 'undefined is not an object'. Here's how my HTML structure ...

Firebase9 cloud storage encountered an issue: [Unhandled promise rejection: ReferenceError: Property 'storage' doesn't exist]

I'm encountering the following issue: [Unhandled promise rejection: Invariant Violation: Failed to construct File: Must pass both parts and name arguments.] I am attempting to upload an image to Firebase cloud storage by selecting it on my phone. T ...

The performance of HTTP requests is significantly decreased in Internet Explorer compared to expected speeds

I am currently developing an Angular site where I need to send a significant amount of data (approximately 1 MB) in an API call. In the Chrome and Firefox browsers, everything works smoothly and quickly, with a response time under one second. However, whe ...

I am having trouble with my jQuery login function not properly connecting to the PHP file

Hey there, I've been working on creating a login system from scratch by following an online tutorial. The initial Javascript is functioning properly as it detects errors when the inputs are empty. However, once I enter text into the input fields and c ...

Buttons in Highcharts

Is there a way to incorporate a button within a highcharts graph? I am working with a bar chart and would like to include a button on the left side of the label, similar to the example shown in this bar chart demo. I want the button to appear before the ...

Discovering the position of an element within an array and leveraging that position to retrieve a corresponding value from a separate array

const STATE = ["TEXAS","CALIFORNIA","FLORIDA","NEW YORK"] const STATE_CODE = ["TX","CA","FL","NY"] With two arrays provided, the first array is displayed in a dropdown menu. The challenge is to retrieve the corresponding state code from the second array ...

Unable to retrieve information from the json-server

For my current project in Backbone.js, I'm utilizing the json-server package to populate it with data. I've created a db.json file containing the data and executed the command json-server --watch db.json. The server started successfully and is ru ...