简体   繁体   中英

Class with common callback in javascript

i want to build a javascript class to register several different functions to execute a single common callback, all registered functions should execute asynchronously and then once all of them are finished, it should execute the defined callback function .

We should also be able to define a maximum time before the callback function executes. For example if we define that as 3000 and it takes more than 3000 ms for all registered functions to return, it should proceed to execute callback function even though the ajax functions have not finished retuning.

To be clear, this code needs to be flexible, standalone and reusable

To assume that any function that we register will implement a call to a function that we define at some point within it mark its completion. for eg. at the end of my function i'll enter myClass.markDone() to let the class know the function has completed executing

Is it possible using javascript or with angular.js and without jquery?

To achieve this take a look at these angular built in modules:

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

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

Here is an example implementation on plunkr:

qAllWithTimeout([
    makePromise(function(callback) {
      // Mock async call 1
      setTimeout(callback, 200);
    }),
    makePromise(function(callback) {
      // Mock async call 2
      setTimeout(callback, 500);
    }),
    makePromise(function(callback) {
      // Long running mock async call 2
      setTimeout(callback, 10500);
    })
  ], 3000)
    .then(function() {        
        $scope.state = 'ready';
    })

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

iam not sure this will work, am not tested. this may give you some idea.

function TestFun(callback, timeout){
    this._callback = callback;
    this._timeout = timeout;
    this._forceFinish = false;
    this.fun_list = [];
    this.RegisterFun = function(fun){
        this.fun_list.push(fun);
    };

    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.watcherFun, 1 );
    };

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

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

//usage

var funMngr = new TestFun(finalFun, 60 * 1000);
funMngr.RegisterFun ( fun1 );
funMngr.RegisterFun ( fun2 );
funMngr.RegisterFun ( fun3 );
funMngr.Start();

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

I asked for clarification in a comment already, but I went ahead and started drafting a solution. Here's what I came up with, hope this is what you meant:

var AsyncBatch = function() {
    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.add(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() {
        // Do something here when all registered callbacks are finished OR the batch timed out
    },

};

Here's how you would use this:

  1. Create an instance of AsyncBatch .
  2. Call .add() as many times as you want, passing a function. This functions should expect a single parameter, which is the callback it should invoke when its job is done.
  3. Call .start() on the AsyncBatch instance. It will execute all runnables asynchronously, as well as start a timer.
  4. If the runnables all finish before the timer runs out, .allDone will cancel the timer and execute .finish() .
  5. If the timer runs out before the runnables, it executes .finish() , and sets the timerId to 0 so that .finish() won't be called again when the runnables all finish.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM