In Javascript, async functions automatically halt all ongoing "threads" when a new function begins

I have a dilemma with multiple async functions that can be called by the user at any point in time. It is crucial for me to ensure that all previously executed functions (and any potential "threads" they may have initiated) are terminated when a new function is invoked. This is necessary because these functions might try to access the same resource, specifically the webcodec decoder, which is not supported if accessed concurrently.

So, how can I achieve this?

My current approach: I am utilizing a global counter that is shared among all functions. At the beginning of each function, I increment and store a copy of this counter. Whenever an async function is triggered, I pass a copy of this counter to it. I then check at the start and end of the subroutine whether the global counter has been modified. However, managing this becomes cumbersome, especially with nested calls to async functions where passing the copied value is required multiple times. Additionally, this method falls short when using async functions not developed by me. Ideally, I want something like:

functionCurrentlyRun = null

async function runFunction(f, args) {
  if (functionCurrentlyRun) {
    stopFunctionAndAllSubthreads(functionCurrentlyRun);
  }
  return await runAndSaveIn(f, args, functionCurrentlyRun) 
}

async function f1(args) {
  return await someAsyncCalls();
}

function f2(args) {
  return await someAsyncCalls();
}

runFunction(f1, 42);
runFunction(f2, 43);

Similar to the behavior exhibited by cancelAnimationFrame, but applicable to arbitrary functions.

EDIT: Following the response, I attempted to implement the following:

<!DOCTYPE html>
<body>
  Hello <button id="buttonstart">Start me</button> <button id="buttonstop">Stop me</button>.
    <script type="text/javascript">
      const wait = (n) => new Promise((resolve) => setTimeout(resolve, n));

      const controller = new AbortController();
      const mainSignal = controller.signal;

      document.getElementById("buttonstart").addEventListener("click", async () => {
        console.log("Should be very first line");
        setTimeout(() => console.log("First timeout"));
        var x = await makeMeAbortIfNeeded(test3(), mainSignal);
        console.log("Last line of the main loop. I received:", x);
      })

      
      document.getElementById("buttonstop").addEventListener("click", () => {
        console.log("Click!");
        controller.abort();
      })

      function makeMeAbortIfNeeded(promise, signal) {
        return new Promise((resolve, reject) =>{
          // If the signal is already aborted, immediately throw in order to reject the promise.
          if (signal.aborted) {
            reject(signal.reason);
          }
          const myListener = () => {
            console.log("Just received a signal to abort");
            reject(signal.reason);
          };
          promise.then(x => {
            signal.removeEventListener("abort", myListener);
            resolve(x);
          });

          signal.addEventListener("abort", myListener);
        });
      }

      async function test3() {
        console.log("[test3] A");
        await makeMeAbortIfNeeded(wait(3000), mainSignal);
        console.log("[test3] B");
        return 42
      }
    </script>
  </body>
</html>

This solution works effectively by replacing all instances of await foo with

await makeMeAbortIfNeeded(foo, mainSignal);
. The only drawback is the challenge of resetting the controller to a non-abort state. It also becomes tedious to rewrite every await, yet no other alternatives seem viable.

Answer №1

There is no easy way to terminate arbitrary tasks without making changes to allow for cancellation. This aligns with the cooperative event loop concurrency model prevalent in most JavaScript platforms, which eliminates the uncertainty of code stopping abruptly during normal execution (unlike preemptive multitasking).

To facilitate task cancellation on the implementation side, the recommended approach is to utilize AbortSignal. Additionally, this can be extended to certain DOM APIs that support cancelation of tasks.

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

What is the proper error type to use in the useRouteError() function in react-router-dom?

In my React project, I am utilizing the useRouteError() hook provided by react-router-dom to handle any errors that may arise during routing. However, I'm uncertain about the correct type for the error object returned by this hook. Currently, I have ...

"Scotchy McScotchface's to-do list application powered

How is the index.html (frontend Angular) being triggered? The tutorial mentioned that by including one of the following routes in route.js, the frontend gets called app.get('*', function(req, res) { res.sendfile('./public/index.html&ap ...

Redux: Double rendering issue in mapStateToProps

I've recently delved into learning Redux, and I've encountered an issue that's been on my mind. import React, { useEffect } from "react"; import { connect, useDispatch } from "react-redux"; import Modal from "../Moda ...

Inaccurate Feedback on Maquest Direction Route API

Currently, I am in the process of implementing the MapQuest API Direction Routing function on my website. However, upon submitting a request to the API, it is returning inaccurate routing points between two destinations. Here is the request form that I am ...

What is the solution for resolving the JavaScript error "TypeError: Cannot read property 'map' of undefined"?

I'm encountering an issue while fetching data from the API and trying to map it to display in a table. The problem is that the fetching process doesn't seem to be working properly, resulting in the state remaining undefined when the page loads. I ...

What is the best way to execute npx commands without the need to add 'npx' before each

For instance, I am able to simply run gulp instead of having to type npx gulp. I can skip the npx and just use gulp How can I achieve this for my own package? Even though I've included mycommand in the package npm bin configuration, I still constan ...

Troubleshooting: Angular version 4.3 Interceptor malfunctioning

I have been trying to implement new interceptors in Angular 4.3 to set the authorization header for all requests, but it doesn't seem to be working. I placed a breakpoint inside the interceptor's 'intercept' method, but the browser didn ...

Tips for positioning the Google Custom Search bar

I am looking to position the Google custom search box on the left side of my website. Currently, I am using a website builder called imxprs and have implemented this code for my custom search box. <script> (function() { var cx = '013012 ...

The Javascript code I wrote is unable to detect the array element that was initially defined in Python

Trying to launch a new browser window through Selenium using driver.execute_script("window.open('');") However, the goal is to open a specific link provided by the user. For this purpose, extracted the link input from an array and inc ...

AngularJS version 1.2.0 is experiencing an issue where the $http service is not properly sending requests

Why is AngularJS 1.2.0 $http not sending requests in $eval? Here is the code you can refer to: http://jsbin.com/oZUFeFI/3/watch?html,js,output ...

React: A guide to properly utilizing PropTypes inheritance

I've created a wrapper component for React Router Dom and Material UI: import Button from '@material-ui/core/Button'; import React from 'react'; import { Link as RouterLink } from 'react-router-dom'; const forwardedLink ...

Is it possible to alter the value of a global variable within a function and switch its value based on a local variable?

Currently, I am facing an issue with changing the value of a global variable dynamically from a function. The variable has a global scope and is also present in the same function as a local variable. However, despite my efforts, I am unable to successful ...

Utilizing Jquery for Enhancing Annotations

I am in the process of developing a website for essay writing tests. I have implemented a feature where users can input their essays using a text area, and now I want to be able to make comments on that text similar to PDF annotations or highlighting. I at ...

Using React to Render a Component with Local Storage Information

I'm in the process of developing a history list component for a form within a react application and encountering difficulties with local storage. The goal is to display a list of previous user inputs from the local storage data. My current approach i ...

Dropzone.js only allows one audio file and one image thumbnail file to be uploaded simultaneously

Is there a way to limit the types of files that can be uploaded through Dropzone.js? Specifically, I want to restrict users to uploading only one image and one audio file. ...

What is the best way to close ngx-simple-modal in angular7 when clicking outside of the modal component?

Can anyone help me with closing the modal in my angular7 app when the user clicks outside of the modal component? I have been using the ngx-simple-modal plugin, and I tried implementing the following code: this.SimpleModalService.addModal(LinkPopupCompone ...

Unable to retrieve information from localhost site using the expressjs API. I have attempted to use both vue-resource and axios in order to get the data without success

Currently diving into the world of VueJS, I decided to embark on a project. My aim is to retrieve data from an ExpressJS server/API. But unfortunately, both vue-resource and axios have been returning status code 0. It seems like my API might not be handli ...

Issue with jQuery's JSON data not being properly transmitted to CodeIgniter (`

Based on my observation, the script provided below seems to be functioning properly: <script type="text/javascript" language="javascript"> $(document).ready(function() { $('#add').bind('keypress', function(e) { if(e.k ...

Stopping video playback when hovering over it

Can anyone help me modify this code so that a video plays only when hovering over it, and stops playing once the hover ends? What changes should I make to the JavaScript portion of the code for this functionality? <div class="padding-box height-40"&g ...

What is the process for confirming the authenticity of lengthy passwords with bcrypt?

"I encountered a problem that I just can't seem to solve. I set up an authentication flow using JWT with access and refresh tokens. The refresh tokens expire after a long time period, and they can be reset to prevent unauthorized use of stolen refresh ...