0

i have created this class to check if the function has been loaded. It works fine, except that I want to avoid using eval to evaluate the function name from a variable. I appreciate any help with this. Thanks.

class scriptLoader {

constructor(fn, max_try) {        
    this.fn = fn; //the func name being passed as a string
    this.count = 0; //init count start value                
    this.max_try = max_try; //the max times to try
}



waitForScriptToLoad() {           
      'use strict';        
        let my_function = eval(this.fn); //this evaluate the string, i.e 'myfunc' to myfunc()                       
      if(typeof my_function === "function") {                        
        my_function();
    } else {                                    
        if(this.count<this.max_try) {
            var that = this;
            setTimeout(function() {that.count++; that.waitForScriptToLoad();},100); //wait 100ms and try again            
        } else {                
            return false;                
        }            
    }
}

}

I instantiate the class like so:

loadData = new scriptLoader('Worker.fetch_form_data', 3);
loadData.waitForScriptToLoad();

1 Answer 1

1

Assuming that the script you're trying to detect will be located on the global object, split the string by .s and check to see if the nested property exists on the global object:

class scriptLoader {

  constructor(propsStr, max_try) {
    this.propsStr = propsStr; //the func name being passed as a string
    this.count = 0; //init count start value                
    this.max_try = max_try; //the max times to try
  }
  waitForScriptToLoad() {
    'use strict';
    const possibleFn = this.propsStr.split('.').reduce((a, prop) => (a?.[prop]), globalThis);
    if (typeof possibleFn === "function") {
      possibleFn();
    } else {
      if (this.count < this.max_try) {
        console.log('retrying');
        setTimeout(() => {
          this.count++;
          this.waitForScriptToLoad();
        }, 100); //wait 100ms and try again            
      }
    }
  }
}

// Dynamic loading of script:
setTimeout(() => {
  window.obj = {};
}, 50);
setTimeout(() => {
  window.obj.nested = {
    fn: () => console.log('fn')
  };
}, 150);


const loadData = new scriptLoader('obj.nested.fn', 3);
loadData.waitForScriptToLoad();

Also note:

  • If using ES2015+ syntax (which you are, and you should be!), best to use const rather than let if you don't require reassignment - avoid var
  • In ES2015+, better to use an arrow function than the that = this antipattern
  • Remember to declare your variables when using them - your loadData is implicitly global since you didn't declare it (consider enabling strict mode at the top level)
Sign up to request clarification or add additional context in comments.

1 Comment

It works, Thanks! But first i got to understand how reduce works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.