Structural code-issue regarding 'setTimeout'


#1

[To those in charge of backend API/code structure within the pc.-architechture]

Once again I seem to find some troubling issues in regards to the workings of ‘setTimeout’.
Within a piece of code, I need to pause a certain execution in relation to calling a function that might run an .enabled command on a model too early.

But anyways here it is:

As I call this line within a function:

self.allCarsGone(); setTimeout(self.setraOn, 300);

I experience that this executes ok:

HtmlHandler.prototype.allCarsGone =  function(){
    this.lamboGone = this.app.root.findByName('Lambo'); this.setraGone = this.app.root.findByName('Setra'); this.ducatoGone = this.app.root.findByName('Ducato');
    this.lamboGone.enabled = false; this.setraGone.enabled = false; this.ducatoGone.enabled = false;
    // Reset all cameras:
    this.activeCameraSplitDucatoUd = this.app.root.findByName('CameraSplitDucato');      this.activeCameraSplitDucatoUd.enabled = false;
    this.activeCameraSplitLamboUd  = this.app.root.findByName('CameraSplitLambo');       this.activeCameraSplitLamboUd.enabled = false;
    this.activeCameraSplitSetraUd  = this.app.root.findByName('CameraSplitSetra');       this.activeCameraSplitSetraUd.enabled = false;    
    this.activeCameraSplitIndFraJ  = this.app.root.findByName('CameraSplitJumpy');       this.activeCameraSplitIndFraJ.enabled =  false;
};
  • while this:
HtmlHandler.prototype.setraOn = function(){
    var app = this.app;
    
    console.log("MSelf"+ app.root.findByName('Lambo')); 
    this.lamboGone = this.app.root.findByName('Lambo');
        this.setraTopEntLvl = this.app.root.findByName('SetraEnt');  this.setraTopEntLvl.enabled = true;  
        this.setra = this.app.root.findByName('Setra');  this.setra.enabled = true;  
        // Venstre side-udsyn ; HalveX/HeleY:
        this.activeCamera1.camera.rect = new pc.Vec4(0, 0, 0.498, 1); 
        // Hoejre side-udsyn ; HalveX/(To Kvarte) HalveY:
        this.activeCameraSplitSetraUd = this.app.root.findByName('CameraSplitSetra'); this.activeCameraSplitSetraUd.enabled = true;       this.activeCameraSplitSetraUd.camera.rect = new pc.Vec4(0.5, 0.5, 0.495, 0.495); 
        this.activeCameraSplitIndFraJ = this.app.root.findByName('CameraSplitJumpy'); this.activeCameraSplitIndFraJ.enabled =  true;      this.activeCameraSplitIndFraJ.camera.rect = new pc.Vec4(0.5, 0, 0.495, 0.495); 
};
  • gives me an error of:

Uncaught TypeError: Cannot read property ‘root’ of undefined

TypeError: Cannot read property ‘root’ of undefined
at HtmlHandler.setraOn (https://launch.playcanvas.com/api/assets/files/Script/HTMLtxtField/htmlHandler.js?id=22760179&branchId=ecf80571-4d50-4ebc-894b-849ad9a16761:192:30)

Motivation: this is not the 1st time that ‘setTimeout’ messes things up for me.
Futhermore: please read Using setTimeout to fade in objects


#2

PS: I just got this workaround to function as wished-for [which should not be confused with a ‘SOLVED’-conclusion >> this being a ‘Feedback’; I guess we all want better architecture instead?]:

  self.allCarsGone();
  for(var timeP=0; timeP<1000000; timeP++){
            var pauseAlittle;
           }
  self.setraOn();

#3

Your setTimeout callback will be in a different scope. Try doing:

var self = this;
setTimeout(function() {
    self.setraOn();
}.bind(this), 300);

Using loops to create a timeout is not a good way of doing things…


#4

Actually, I think you would do either:

setTimeout(function() {
    this.setraOn();
}.bind(this), 300);

Or:

var self = this;
setTimeout(function() {
    self.setraOn();
}, 300);

But yes, this all originates from a misunderstanding of this. Maybe try reading this:


#5

Also in hindsight, if you want to delay something I always like doing a quick, empty tween instead because it runs in the update loop of the app versus in the window. So if the tab is inactive, the timer stops counting down and resumes as normal when the app is active again.

this.app.tween({}).to({}, 1, pc.Linear)
    .on('complete', function() {
        // do whatever here
    }, this).start();

#6

Because …?


#7

Presumably because it’ll execute at different speeds on different devices. :slight_smile: