Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript class member function calling member function by setInterval, couldn't access member variable

I'm trying to make a simple task queue with setInterval with a linked-list. I created a class with linkedlist and a setInterval function will keep calling a member function to consume the job.

function job_queue(){
    this.job = null;
    this.pointer = this.job;
    this.job_dispatcher = null; 
    this.length = 0;
}
job_queue.prototype.add_job = function( job ){
    if( this.job == null ){
        console.log('1st');
        this.job = {
            job:job,
            next:null
        };
        this.pointer = this.job;
        this.length = 1;
    }else{
        console.log('2nd');
        this.pointer.next = { 
            job:job,
            next:null
        };
        this.pointer = this.pointer.next;
        this.length++;
    }
};

job_queue.prototype.event_handler = function(){
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }

}

job_queue.prototype.start_dispatch = function(){
    if( this.job_dispatcher == null ){
        console.log( this.event_handler );
        this.job_dispatcher = setInterval( this.event_handler,1000);
    }
}



var jq = new job_queue();
function a(){
    console.log('hi');
};
function b(){
    console.log('hi2');
}
jq.add_job(a);
jq.add_job(b);
jq.add_job(a);
jq.start_dispatch();

However, when the event_handler function gets called , the program crashes with the log

 if( typeof this.job['job'] == 'undefined'){

It seems like it can not access the member variable by calling member function with setInterval. I would like to ask what exactly happened with these lines of code and how can I achieve the goal?

like image 800
Jian Avatar asked May 13 '26 19:05

Jian


2 Answers

As others have pointed out, setInterval() calls your function in a different context. This means that the value of this within the function passed to setInterval() (in this case, event_handler()) will not be pointing to the correct object.

A great solution to this problem is JavaScript's bind function:

this.job_dispatcher = setInterval(this.event_handler.bind(this), 1000);
like image 189
Andy Barron Avatar answered May 16 '26 09:05

Andy Barron


setInterval() doesn't work with this. See here: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval#The_this_problem

Code executed by setInterval() is run in a separate execution context to the function from which it was called. As a consequence, the this keyword for the called function will be set to the window (or global) object, it will not be the same as the this value for the function that called setTimeout.

You can call your method inside an anonymous function like this:

function job_queue(){
    this.job = null;
    this.pointer = this.job;
    this.job_dispatcher = null; 
    this.length = 0;
}
job_queue.prototype.add_job = function( job ){
    if( this.job == null ){
        console.log('1st');
        this.job = {
            job:job,
            next:null
        };
        this.pointer = this.job;
        this.length = 1;
    }else{
        console.log('2nd');
        this.pointer.next = { 
            job:job,
            next:null
        };
        this.pointer = this.pointer.next;
        this.length++;
    }
};

job_queue.prototype.event_handler = function(){
        
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }

}

job_queue.prototype.start_dispatch = function(){
    var self = this;
    if( this.job_dispatcher == null ){
        console.log( this.event_handler );
        this.job_dispatcher = setInterval( function(){self.event_handler()},1000);
    }
}



var jq = new job_queue();
function a(){
    console.log('hi');
};
function b(){
    console.log('hi2');
}
jq.add_job(a);
jq.add_job(b);
jq.add_job(a);
jq.start_dispatch();
like image 41
Julien Grégoire Avatar answered May 16 '26 07:05

Julien Grégoire



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!