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

Utilizing Next.js to conditionally display data

My current challenge involves rendering data fetched from an API. The data is in JSON format, and I have a conditional logic to push a specific element based on the fetch result. {status: 'success'} If the fetch fails, I need to handle it by pus ...

The hyperlink function is not operational in Gmail attachments

Using an anchor tag to navigate to a specific section within the same page works perfectly when the HTML file is on my local machine. However, when I attach the file in Gmail and open the attachment, it doesn't work. Why is this happening? How can I m ...

Is it necessary to close the browser for jQuery to reload an XML document?

I've successfully used jQuery's $.ajax to retrieve an xml value in my code. However, I'm facing an issue where any changes made to the xml document are not reflected upon a browser refresh. Specifically, the new saved xml value xmlImagePath ...

Transferring a FormData object between different servers

When attempting to submit the same form at a URL on the same server, it successfully goes through. $("#ticketForm").submit(function(e){ e.preventDefault(); var formData = new FormData(this); for (var p of formData) { console.log(p); ...

File writing issues are plaguing NodeJS, with middleware failing to function as well

I am facing a challenge with my middleware that is supposed to write JSON data to a file once the user is logged in. However, I am encountering an issue where no data is being written to the file or displayed on the console when the function is executed. ...

Error 4 encountered when attempting to upload files using Ajax to a PHP server

On my website, there is a form that looks like this: <form style="width:100%; clear:both; margin-top:50px; background:#fff; border:1px solid green" id="upload_form" enctype="multipart/form-data" class="form" action="" method="post"> <fieldse ...

Calculate the length of a JSON array by using the value of one of its

What is the most efficient way to obtain the length of a JSON array in jQuery, based on the value of its attribute? As an illustration, consider the following array: var arr = [{ "name":"amit", "online":true },{ "name":"rohit", "online":f ...

Are you experiencing issues with the .submit() function when used in conjunction with other

Currently, I am working on a survey form that incorporates JQuery to dynamically display or hide fields based on user selections. //FORM CONDITIONALS: This script is responsible for hiding all the helpfulness radios and only displaying them when "Yes" fo ...

The JSON.stringify() function helps to convert data into a JSON-formatted string, avoiding any potential "c

connection.query( 'SELECT DeskName FROM desks WHERE stat = ?',["Booked"], function(err, rows){ if(err) { throw err; }else{ try{ var dataToParse = new Array(); dataToParse = rows; res.render('workspaces.html',{parsedArray : JS ...

"Unexpected outcome: Angular's HTTP request for a JSON file yields an undefined

Learning Angular has been a challenging experience for me. I am currently working on reading a json file into a chart on my main app page to visualize temperature data from my PI. Despite trying various methods found online, I have not been successful so f ...

Steps for submitting a form once all inputs have been verified

$('#f_name, #l_name').change(function(){ if($(this).val().length < 2) { $(this).css('border', '1px solid red'); alert('names must be at least 2 symbols'); check ...

The Discord.js bot is unable to send messages in embedded format

I created a Discord bot using discord.js with multiple commands, including three commands with embed forms. One command, "help", works perfectly fine, but the other two are not functioning properly. All of them have the same main code structure, specifical ...

VueJS 3 custom Checkbox fails to update UI upon clicking

I'm attempting to implement a customized checkbox using Vue 3 and the composition API based on this example. However, despite confirming through devtools that all my props and bound data are successfully passed from the parent component to the child c ...

Error: Unable to change image -- TypeError: Cannot assign value to null property 'src'

As I work my way through the textbook for one of my classes, I am practicing by building an image swapping page. The concept is simple - clicking on a thumbnail swaps out the main image and enlarges it as if it were linking to another web page. Despite fol ...

Troubleshooting Rails 5 and AJAX modal login issues

In my pursuit of implementing ajax authorization in Rails 5.0.0, I have tried numerous guides without success. Here's what I've done: 1. Cloned the Devise Controllers Users::SessionsController < Devise::SessionsController def create re ...

Tips for positioning a div element within the body of a webpage to maintain a predetermined height and width

Currently, I am developing a single-page application using AngularJS. I have specific routes in mind where I want to introduce new HTML templates. To accomplish this, I have created a container labeled with the ID #main positioned between two navbars (he ...

Guide on obtaining an obscure style guideline in MS Edge using JavaScript

If you are looking to utilize the object-fit CSS rule, keep in mind that it is not supported in MSIE and MS Edge Browsers. While there are polyfills available for IE, none of them seem to work in Edge from my experience. For instance, the polyfill fitie b ...

The output from VScode-Code-Runner is limited to just the directory, with no additional

I have successfully set up Code Runner with the following configurations in the Executer Map: { "explorer.confirmDelete": false, "[html]": { "editor.defaultFormatter": "vscode.html-language-features" }, "[javascript]": { "e ...

Delayed response of text effects in JQuery on page load

Within my rails app, I have the following code snippet: window.onload = -> $("#mycontainer").typewriter() $("#div1").fadeIn("slow") This code snippet interacts with the following block of content: <blockquote class="pull-left"> < ...

Signal check indicates that the Internet connection has been restored

One of the key requirements for my app is to load data into a database, which necessitates having an active Internet connection. I have been contemplating what to do in case of network failure - perhaps I can store the data locally on the device and synch ...