setInterval in module not working

Posted on
  • Hey all, I'm trying to write my first module for the pixl and I'm having difficulties with setInterval in the modules function. I was closely following the writing modules page.

    I use the code below to develop in the WebIDE. The beep function works fine, so does the second function that just calls the beep function. But then the third function involves calling beep from a setInterval. And that is not working.

    What am I doing wrong?

    var exports={};
    var PIN;
    var VOLUME;
    
    function SOUND(pin,volume){
    	this.PIN = pin;
    	this.VOLUME = volume;
    }
    
    SOUND.prototype.beep = function(freq,time){
      analogWrite(this.PIN,this.VOLUME,{freq : freq});
      setTimeout(function(){analogWrite(this.PIN,0); },time);
      print("beep");
    };
    
    SOUND.prototype.multibeep_works_fine = function(freq,time,nr){
      this.beep(freq,time);  
    };
    
    SOUND.prototype.multibeep_works_not = function(freq,time,nr){
      setInterval(function(){ this.beep(freq,time); }, 1000);
    };
    
    exports.setup = function(pin,volume){
    	return (new SOUND(pin,volume));
    };
    
    var s = exports.setup(A0,0.005);
    
    //works
    s.beep(1000,10);
    
    //works
    s.multibeep_works_fine(1000,100,1);
    
    //does NOT work?
    s.multibeep_works_not(1000,100,1);
    
  • Sat 2020.01.25

    @Raik, is the above code in one monolithic file, as the modules file, or is there a calling page?

    Is the desire to call a separate module page, or to learn how to develop a single file to develop the module code?

    It's possible that L21 needs to also pass 'freq' 'time' as arguments - e.g. the function parameter list isn't present in order to pass the argument values.

    Haven't tested, but thinking about it, I believe the above to be true. One could have included a console.log( freq, time ) statement within the L21 function to see if the values are 'undefined' or used the debugger.



    Google to the rescue!

    google:    passing function arguments using javascript setinterval site:w3schools.com

    See example page bottom:

    https://www.w3schools.com/jsref/met_win_setinterval.asp



    Nothing to do with module development, language syntax.

  • This is about object reference.

    change this. to SOUND. in line 21.

    setInterval(function(){SOUND.beep(freq,time); }, 1000);
    

    or add ‘that’

    
    function SOUND(pin,volume){
        this.PIN = pin;
        this.VOLUME = volume;
        var that = this;
    }
    
    SOUND.prototype.multibeep_works_not = function(freq,time,nr){
      setInterval(function(){ that.beep(freq,time); }, 1000);
    };
    
  • Sun 2020.01.26

    @MaBe, (haven't tested) but wouldn't var 'that' L5 need to be global in order for L9 to see object 'that'? . . . or maybe (guessing) SOUND.that.beep(?

    My belief was the (missing) argument syntax as shown in that link.

  • @Raik, is the above code in one monolithic file, as the modules file, or is there a calling page?

    It's the piece of code from the editor I upload to experiment with modules. Later on this will be put to the file system as one file (that's the plan).

    It's possible that L21 needs to also pass 'freq' 'time' as arguments

    Well it's referring to the beep function, that only has two argument. So it should work, right?

    change this. to SOUND. in line 21.
    or add ‘that’

    Thanks for the hint: creating a new reference for this worked, though I'm not sure why?

    Is it because the module code runs in its own scope? And this is not referring to SOUND but rather to the main scope?

    When a module is loaded, Espruino executes the file in its own scope
    (from Writing Modules)

  • It's "just classic javascript this" :) It's not a because "the module code runs in its own scope".
    At line 21, the this inside the callback function inside the setInterval is not what you would expect. Basically nothing / global scope, because you did not specify the this argument, or used bind. Just JS default behavior. :)
    That's why code was littered with var that = this. But now it's kind-of sort-of solved in ES6 / typescript code.

  • Glad you got this sorted - this is one of the classic JavaScript pitfalls. function() { ... } doesn't remember the value of this.

    The easiest way to think of it (I find) is that JS is dumb, and when you use this, JS looks back at how the function was called (and not the function itself):

    var a = {
     b :42,
     c : function() { print (this.b); }
    };
    
    a.c(); // prints 42
    a["c"](); // prints 42
    var z = a.c;
    z(); // doesn't work
    
    var somethingelse = {
     b :"uh oh",
     c : a.c
    };
    somethingelse.c(); // prints "uh oh"
    

    However arrow functions do remember the value of this so in your case if you did:

    SOUND.prototype.multibeep_works_not = function(freq,time,nr){
      setInterval(() => { this.beep(freq,time); }, 1000);
    };
    

    Then it'd work :/

  • Thanks for the follow up!

    I kinda realized JS is "dumb", but expected a behavior similar to other language and got frustrated.
    Oh well, at least I learned something.

    I'll try out the arrow functions.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

setInterval in module not working

Posted by Avatar for Raik @Raik

Actions