Discord
Login
Community
DARK THEME

Defined Execution Order Of Files?

Is there a defined execution order of files? I'm trying to get Gamekeeper working, but I either need to know and manipulate the execution order of the files or mash everything into one file. It's not alphabetical order, so what is it?

There is no defined order of code execution for JavaScript code.

What's worse, this order changes.

If you have 4 files, each with one function that prints a message in the console, you can see any arrangement of these messages in the console.

See the race of conditions - forum thread.

It's even worse for classes because a class that refers to an ancestor or another class that is in another file that MicroStudio did not analyze - the code for this class will not be in the virtual machine, but you will not receive an error message.

This is very frustrating because your code could work, you change something in file A, and the code does not work, you add a space (or another character that does not affect the code) in file B and the code works. You add something again (e.g. a new class) and the code does not work. You have to deduce which class has the error.

As an error, it may be a syntax error, but it may be an error in the scope of vision of other classes (the order in which MicroScript loads files). You need to determine whether the class sees other classes correctly, or sees its ancestors correctly.

Additionally, the whole situation has the character of a cascading growth. Imagine that you have class A, class B, and the rest of the classes that inherit from class B. If for some reason class B does not see class A, then all classes inheriting from B will not be created in the virtual machine (as if they were not in the code). Here you will quickly diagnose the problem. But what to do if you use a class (let's call it Game) that has objects (fields) of 20 other classes. If one of these 20 classes is not added to the virtual machine, the Game class will not be added either, and good luck diagnosing the problem.

I'll write it again - it's very frustrating and you have almost no feedback from MicroStudio about what's wrong.

However, I managed to work out a mechanism with GPT that protects the code from race conditions.

Here's how to proceed when creating classes in JavaScript.

temple_class file >> ( I'm leaving the contents of the class for demonstration purposes only. )

// javascript

global.regTemplate = function() {
  let TemplateClass;

  return function() {
    if (!TemplateClass) {
      TemplateClass = class Template {
 
        static count = 0;  
        constructor(data) {
          if (data === undefined) { data = {} }
          if (typeof this.constructor.count === 'undefined') {
            this.constructor.count = 0;
          }
       //   this.instanceNumber = this.constructor.incrementCount();
          this.constructor.count += 1;
          this.instanceNumber = this.constructor.count;
          this.classname = this.constructor.name;  
          this.name = data.name !== undefined ? data.name : `${this.classname}${this.constructor.getCount()}`;
          this.parent = data.parent !== undefined ? data.parent : null;
        }
        
        destroy() {}
       
        static incrementCount() {
          if (!this.count) {
            this.count = 0;
          }
          this.count += 1;
          return this.count;
        }
      
        static getCount() {
          return this.count || 0;
        }
        
        getClassName() {
          return this.constructor.name;
        }
        
        print(string) {
          global.print( this.classname  + "(" + this.name + "):" + string);
        }
        
        toJSON() {
            return {
              ...this,
              className: this.getClassName(),
            };
        }
        
        serialize() {
            return JSON.stringify({
              classname : this.classname,
              name: this.name,
            });
        }
      
        static deserialize(serialized) {
            const data = JSON.parse(serialized);
            const template = new this(data);
            return template;
        }
        
      }
    }
    return TemplateClass;
  };
};

MyClass file >>

// javascript 

global.regMyClass = function(){
  let MyClass;
  return function() {

    if (!MyClass) {    
      const Template = global.regTemplate();
      const MyClassID = 1001;
      
      MyClass = class My extends Template{
        #type = MyClassID;
        #x;
        #y;
        static count = 0;
        constructor(data){
          super(data);
          this.graph = data && data.graph !== undefined ? data.graph : null;// Graphics
          this.body = data && data.body !== undefined ? data.body : null;   // Physics 
          this.x = data && data.x !== undefined ? data.x : 0;
          this.y = data && data.y !== undefined ? data.y : 0;
        }
        
        update() {
          // Update graphics based on physical data
          const position = this.body.position;
          const rotation = this.body.angle;
      
          // Update graphic position and rotation
          this.graph.position.set(position.x, position.y);
          this.graph.rotation = rotation;
        }
      
        setPosition(data) {
          Matter.Body.setPosition(this.body, data);
        }
        // 
        updateRotation() {
          this.graph.rotation = this.body.angle;
        }
        
        get x(){
          return this.#x;
        }
        
        set x(value){
          this.#x = value;
          if (this.graph != null) this.graph.position.x = this.#x;
        }
        
        get y(){
          return this.#y;
        }
        
        set y(value){
          this.#y = value;
          if (this.graph != null) this.graph.position.y = this.#y;
        }
      }
    }
    return MyClass;
  }
};

lib file >>

// javascript 
global.regNameLibary = function(){
  // Matter.js
  const Composite   = global.Matter.Composite;
  // lib
  const MyClass     = global.regMyClass       ();
  const Template    = global.regTemplate      ();
  
  return { 
    Composite,
    MyClass, 
    Template};
}

main file >>

init = function()
   nameLibary = regNameLibary
end

All classes from the library will be on the path

  a = new nameLibar.MyClass()

Additionally, you can make the library itself add itself to the global variable by automatically executing the function.

// javascript 
global.nameLibary = (function(){
  // Matter.js
  const Composite = global.Matter.Composite;
  // lib
  const MyClass = global.regMyClass();
  const Template = global.regTemplate();

  return ({ 
    Composite,
    MyClass, 
    Template
  });

})();

And it's not necessary to call the library registration in the main file.

Lunaryss has published many libraries that are very good (javascript language). However, when you combine two or more libraries, they stop starting correctly due to race conditions.

Now that I think about it, scripts could probably depend on each other with promises. I haven't tested it, but this should work:

// lib/dependency.js

window.MyLibrary ||= { resolve: {} };

if (!("dependency" in MyLibrary)) {
  MyLibrary.dependency = Promise.resolve(undefined);
} else {
  MyLibrary.resolve.dependency();
}

class Dependency {
  sayHello() {
    global.print("Hello, World!")
  }
}

MyLibrary.Dependency = Dependency;
// lib/extends_dependency.js

window.MyLibrary ||= { resolve: {} };

if (!("dependency" in MyLibrary)) {
  MyLibary.dependency = new Promise((resolve, reject) => {
    MyLibary.resolve.dependency = resolve;
  });
}
await MyLibrary.dependency;

class ExtendsDependency extends MyLibrary.Dependency {
  function sayGoodbye() {
    global.print("Goodbye!")
  }
}

MyLibrary.ExtendsDependency = ExtendsDependency

In lib/dependency.js:

  • If the dependency promise exists, resolve it. Otherwise, create and resolve it.
  • Define the Dependency class.

In lib/extends_dependency.js:

  • If the dependency promise doesn't exist, create it.
  • Wait for the dependency promise.
  • Define the ExtendsDependency class, which extends the Dependency class.

This way, the classes should always be defined in the correct order, even if the order of execution changes.

There could probably also be an event-based way of doing things:

// lib/dependency.js

MyLibrary ||= { onDependencyLoaded: [] };

class Dependency {
  sayHello() {
    global.print("Hello, World!")
  }
}

MyLibrary.Dependency = Dependency;

for (const trigger of MyLibrary.onDependencyLoaded) {
  trigger();
}
// lib/extends_dependency.js
MyLibrary ||= { onDependencyLoaded: [] };

function main() {
  class ExtendsDependency extends MyLibrary.Dependency {
    function sayGoodbye() {
      global.print("Goodbye!")
    }
  }
  
  MyLibrary.ExtendsDependency = ExtendsDependency;
}

if ("Dependency" in MyLibrary) {
  main();
} else {
  MyLibrary.onDependencyLoaded.push(main);
}

In lib/dependency.js:

  • Define the Dependency class.
  • Execute all onDependencyLoaded triggers.

In lib/extends_dependency.js:

  • Define a function to define the ExtendsDependency class, which extends the Dependency class.
  • If lib/dependency.js has loaded, execute the function. Otherwise, add it as an onDependencyLoaded trigger.

Post a reply

Progress

Status

Preview
Cancel
Post
Validate your e-mail address to participate in the community