JavaScript class with callback function commonly used

I am looking to create a JavaScript class that can register multiple functions to run with a common callback. Each registered function should run asynchronously, and once they have all completed, the specified callback function should be executed.

In addition, I would like to set a maximum time limit for the callback function to execute. For example, if this limit is set to 3000 milliseconds and the registered functions take longer than 3000 ms to return, the callback function should still proceed without waiting for all functions to finish their execution.

The code needs to be flexible, standalone, and reusable. It should assume that any registered function will call a specific function we define to mark its completion. For example, at the end of a function, I would use myClass.markDone() to signal to the class that it has finished executing.

Is it possible to achieve this using JavaScript or Angular.js without relying on jQuery?

Answer №1

If you want to accomplish this task, explore these pre-built modules within Angular:

https://docs.angularjs.org/api/ng/service/$q

https://docs.angularjs.org/api/ng/service/$timeout

Check out this example implementation on Plunkr:

qAllWithTimeout([
    makePromise(function(callback) {
      // Simulate asynchronous call 1
      setTimeout(callback, 200);
    }),
    makePromise(function(callback) {
      // Simulate asynchronous call 2
      setTimeout(callback, 500);
    }),
    makePromise(function(callback) {
      // Lengthy simulated asynchronous call 2
      setTimeout(callback, 10500);
    })
  ], 3000)
    .then(function() {        
        $scope.state = 'ready';
    })

http://plnkr.co/edit/hNo9kJmKIR4hEoNk9pP2?p=preview

Answer №2

Unsure if this code will work as it has not been tested yet. It may provide some insights.

function TestFunction(callback, timeout){
    this._callback = callback;
    this._timeout = timeout;
    this._forceFinish = false;
    this.fun_list = [];
    this.RegisterFunction = function(func){
        this.fun_list.push(func);
    };

    this.startCount = -1;
    this.finishCount = 0;

    this.timeOutFunction= function(){
        this.startCount++;
        fun_list[this.startCount]();
        this.commonCallback();
    }
    this.Start = function(){
        for(var i=0; i <this.fun_list.length ;i++){
            setTimeout( this.timeOutFunction, 0);
        }
        setTimeout( this.watcherFunction, 1 );
    };

    this.commonCallback = function(){
        if( this._forceFinish){
            this._callback();
        }else{
            this.finishCount++;
            if(this.finishCount == this.fun_list.length ){
                this._callback();
            }
        }
    }

    this.watcherFunction = function(){
        if( this._timeout !=0 ){
            this._timeout-1;
            setTimeout( this.watcherFunction, 1 );
        }else{
            this._forceFinish = true;
            this.commonCallback();
        }
    }
}

//usage

var funcManager = new TestFunction(finalFunction, 60 * 1000);
funcManager.RegisterFunction ( func1 );
funcManager.RegisterFunction ( func2 );
funcManager.RegisterFunction ( func3 );
funcManager.Start();

function finalFunction(){
    alert("all functions executed" );
}

Answer №3

I previously sought clarification in a comment, but proceeded to create a solution nonetheless. Below is the draft I came up with based on your request:

function AsyncBatch() {
    this.runnables = new Set();
}

AsyncBatch.prototype = {
    runnables: null,
    timeoutId: 0,

    add: function(runnable) {
        this.runnables.add(runnable);
    },

    start: function() {
        this.timeoutId = window.setTimeout(this.timeout.bind(this), 3000);

        let promises = [];
        for (let runnable of this.runnables) {
            promises.push(new Promise(resolve => {
                runnable(resolve);
            }));
        }
        Promise.all(promises).then(() => this.allDone());
    },

    allDone: function() {
        if (this.timeoutId === 0) return;
        window.clearTimeout(this.timeoutId);
        this.finish();
    },

    timeout: function() {
        this.timeoutId = 0;
        this.finish();
    },

    finish: function() {
        // Actions to be taken when all callbacks are completed or the batch times out
    },
};

To utilize this solution, follow these steps:

  1. Instantiate an AsyncBatch object.
  2. Use .add() method as needed to add functions that expect a callback parameter upon completion.
  3. Invoke .start() on the instance of AsyncBatch to initiate asynchronous execution of all added functions and start a timer.
  4. If all functions complete before the timer expires, .allDone() will halt the timer and call .finish().
  5. If the timer elapses before all functions complete, .finish() will be called and the timerId will be set to 0 to prevent redundant calls to .finish().

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 best way to retrieve a collection of DOM elements in JSX?

I'm in need of rendering certain components only if a specific condition is met. To achieve this, I have written the following inside the render() method: return ( <div className={classes.root}> {registrationScreen && ( * ...

Dealing with incoming data in a yii2 RESTful service

When sending an array using $http post, I follow this approach: var results = services.transaction('orderdetails/insert', {customer_id: $scope.order.customer_id, data: $scope.orderDetail}); The variable $scope.orderdetail ...

A comprehensive guide on displaying data in Angular using an API

I have encountered an issue while trying to display data from an API in the 'home.component.html'. Although my 'home.component.ts' successfully fetches the data from the service, I'm facing difficulty rendering it in 'home.com ...

Scrolling the Ionic framework to a position below zero

My ion scroll is synchronized with another component for scrolling. I achieve this by using the function scroll1.scrollTo(left, top, false); Unfortunately, this function does not allow scrolling to a negative position, such as scroll1.scrollTo(left, -50, ...

ReactJS: Checkbox status remains consistent through re-rendering of Component

I have developed a JSfiddle example Initially, this fiddle displays a list of checkboxes based on the passed props to the component. When you click the Re-render button, the same component is rendered with different props. Now, please follow these steps- ...

Updating parameter value upon the execution of an internal function in Javascript

How can I log the text from a textbox to the console when a button is clicked in this code snippet? <body> <input type="text" id="ttb_text" /> <script type="text/javascript"> function AppendButton() { var _text = ''; ...

Is it possible to analyze an API call and determine the frequency of a specific field?

Code: var textArray = new Array(); var allText = results.data._contained.text; for (var i = 0; i < allText.length; i++) { var text1 = allText[i]; var textHtml = "<div id='text_item'>"; textHtml += "& ...

Utilizing Angular UI-Router for Efficient Multiple Named Views Management

Desired Functionality Working with AngularJS and the Angular UI-Router. I aim to enable two child states to share a parent state. The child states should populate a ui-view in the parent state's view with their own content. One of the child states ...

How can I dynamically populate my select field with JSON data using React.js?

My goal is to fetch data from an API and use the 'symbol' JSON field as options for a select dropdown. However, I'm encountering an issue: 'TypeError: Cannot read property 'length' of undefined.' Beneath my code, I' ...

Apply jQuery styling to new select box on page in order to maintain consistent styling throughout

I've encountered an issue with my jQuery select box styling. It appears to work perfectly on the initial page load, but when new content containing a select box is dynamically loaded onto the page, the styling doesn't get applied to it. Can anyo ...

Using CSS to style a repeater that only shows the initial record

After adding a DIV tag with the ID "mbody" in the below code, only the first record retrieved from the database is displaying. However, when I remove the DIV tag mbody, everything works fine. But for formatting purposes, I want to keep using the DIV tag. U ...

Retrieve data from a MySQL database with multiple values stored in a single row

In my project, I have implemented a filter functionality using PHP and jQuery/AJAX, where my table of products is structured as follows: |id|status|name|colors_id| ------------------- | 1| 1 | toy| 1,4,7 | <-- these are the IDs of various filters, ...

What is the best way to loop through ng-repeat with key-value pairs in order to display each

I need to loop through and show the data stored in "detailsController". <div ng-controller="detailsController"> <div ng-repeat="data in details" id="{{data.Id}}"> {{data.Name}} </div> </div> ...

Associate the URL with the object to retrieve the corresponding object

When iterating through this array, I currently loop through it in the following manner: {props.choosenMovie.characters.map((characters) => ( <p>{characters}</p> /* This displays the URL of course */ ))} The URLs contain a name object th ...

Error: Unable to locate module: Material-UI - Please check the path and try again

Encountering this error: Error message: Failed to compile ./node_modules/@material-ui/core/Modal/Modal.js Module not found: Can't resolve '@babel/runtime/helpers/builtin/assertThisInitialized' in 'C:\Users\rifat\ ...

Update the html() function to include any content that has been typed into a

I have a webpage structured like this: <div id="report_content"> Some information <textarea name="personal"></textarea> <b>Other information</b> <textarea name="work"></textarea> </div> Whe ...

Learn how to retrieve data using the $.ajax() function in jQuery and effectively showcase it on your HTML page

Can someone assist me with extracting data from https://jsonplaceholder.typicode.com/? Below is the AJAX call I'm using: $.ajax({ url: root + '/posts/', data: { userId: 1 }, type: "GET", dataType: "json", success: function(data) { ...

Tips for achieving expansion of solely the clicked item and not the whole row

I am trying to create a card that contains a cocktail recipe. The card initially displays just the title, and when you click on a button, it should expand to show the full menu and description. The issue I'm facing is that when I click on one element, ...

tips for remaining in modal window post form submission

I have a form within a modal window. I am using ajax to load content in the same modal window, but the issue is that it redirects to the main page after submitting the form. How can I ensure that the modal window stays open even after the form submission? ...

Loading remote content on a server for my Firefox OS application - On the Web and FxOS device

I haven't come across this issue in any forum, so I decided to reach out here. I'm encountering a problem with my FirefoxOS app on my FirefoxOS device (Geeksphone Developer Preview) when trying to retrieve remote content from the server. I am m ...