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.