Fire event with this.emit(...)?

Posted on
  • Hi Everyone! On Puck I try to organize communication between objects with events (see Object.emit and discussion here). However, I cannot emit an event within a prototype function with 'this'. Thus if e.g. I have two step up modules, I cannot subscribe directly to each of them, and need to add either a module id as an event argument or additional empty object (see below).

    In comments here is what I'd want:

    function aClass() {};
    
    aClass.prototype.testEmit = function() {
      setTimeout(()=>aClass.emit('TestEvent'),­ 1000); //this.emit(...) here will not emit!
    }
    
    var a = new aClass();
    aClass.on('TestEvent', ()=>console.log('Got event')); //would like 'a.on(...)'
    a.testEmit();  // get 'Got event' printed in log
    
    var a1 = new aClass();
    a1.testEmit(); // get another 'Got event' printed in log
    

    Here is a way round with an empty object:

    function aClass() {
      this.emitter = {};
    };
    
    aClass.prototype.testEmit = function() {
      setTimeout(()=>this.emitter.emit('TestEv­ent'), 1000); //now it works
    }
    
    var a = new aClass();
    a.emitter.on('TestEvent', ()=>console.log('Got event')); //now we subscribe only to a
    a.testEmit(); //get 'Got event' in console
    
    var a1 = new aClass();
    a1.testEmit(); //get nothing
    

    Why can't I use this.emit(...)?

  • Hm.. For whatever reason, it works now.. I'm a bit embarrassed.. Just for reference, code is here:

    function aClass() {};
    aClass.prototype.testEmit = function() {
      setTimeout(()=>this.emit('TestEvent'), 1000); 
    }
    var a = new aClass();
    a.on('TestEvent', ()=>console.log('Got event')); 
    a.testEmit();  // get 'Got event' printed in log
    var a1 = new aClass();
    a1.testEmit(); // event here is not caught
    
  • Sat 2021.03.27

    @AndreyVS    While searching for an answer to #1, our posts crossed:

    Why can't I use this.emit(...)?

    I'm now puzzled also, as:

    ref: 'You cannot rebind this in an arrow function.'

    violates ECMAScript specification:

    https://stackoverflow.com/questions/3330­8121/can-you-bind-this-in-an-arrow-funct­ion

    https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Functions/Arro­w_functions





    It seems the L3 ()=>this.emit('TestEvent') arrow function is bound to the setTiemout() object, or maybe this is bound to the application environment Global scope and not the L2 aClass.prototype.testEmit object as desired. This might explain why it just works, and not actually a specification violation.



    Incidentatlly, Post #2 L1 should not terminate with a semi-colon, and L4 should.

  • 'However, I cannot emit an event within a prototype function with 'this''

    After playing with these snippets, I'm now not entirely sure what the original intent is/was.

    http://www.espruino.com/Reference#l_Obje­ct_on

    In post #2 L6, registers an arrow function response to object a

    Missing, following L8 is the event listener registration for object a1

    So when L9 executes, there isn't the registered listener to respond to the console.


    'Thus if e.g. I have two step up modules, I cannot subscribe directly to each of them'

    It is possible that as the second 'Got event' never occurs, (comment L9) compared to the test results in post #1 is just simply tripping up thinking, as there isn't a means (an on() method attached to a1) to view the second event?

  • Many thanks, Robin! However, seems that this correctly references the instance, also supported by stackoverflow answer:

    Arrow functions do not have a this value of its own, when you access it, you are accessing the this value of the enclosing lexical scope.

    We can see if we print it out:

    function aClass(id) {
      this.id = id;
    }
    
    aClass.prototype.testEmit = function() {
      setTimeout(()=>{console.log('This is ', this); this.emit('TestEvent')}, 1000); 
    };
    
    var a = new aClass('a');
    a.on('TestEvent', ()=>console.log('a emitted')); 
    a.testEmit();  // get 'This is aClass {id = a...}' and the event is caught with 'a emitted' 
    
    var a1 = new aClass('a1');
    a1.on('TestEvent', ()=>console.log('a1 emitted')); 
    a1.testEmit(); // get 'This is aClass {id = a1...}' and the event is caught with 'a1 emitted' 
    

    By contrast, if we replace arrow function in L6 with function(), this will reference the global object, which does not have emit(), and code crashes.

    setTimeout(function(){console.log('This is ', this); this.emit('TestEvent')}, 1000);  //crashes
    

    To summarize for reference, this can be used, but should be cautious when calling setTimeout:

    function aClass() {}
    
    aClass.prototype.testEmit = function() {
      this.emit('TestEvent'); 
    };
    
    var a = new aClass();
    var a1 = new aClass();
    
    a.on('TestEvent', ()=>console.log('a emitted')); 
    a1.on('TestEvent', ()=>console.log('a1 emitted')); 
    
    setTimeout(a.testEmit.bind(a), 500); // can use, get printed 'a emitted'
    setTimeout(()=>a1.testEmit(), 1000); // can use, get printed 'a1 emitted'
    
    setTimeout(a.testEmit, 1500); //crashes, as *this* in testEmit definition references global object, not a
    
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Fire event with this.emit(...)?

Posted by Avatar for AndreyVS @AndreyVS

Actions