I have a proxied object where I intercept get(). If the requested attribute does not exist then I load it from a script. That part works fine. But if a class is referenced then the instantiation goes ahead before the value gets loaded. The obvious answer is to use callbacks, but I can't find a way to intercept the construct() operation or some other means to hook in a callback to delay the instantiation process until the script load fully completes.
I do understand callbacks, fetch(), import() but the answers relating to any of those do not address the race condition when using Proxied objects.
The following has been tested with Chrome v71. I am not interested in compatability with other browsers, nor the use of jQuery or any other framework. I would have thought that ES6 functionality would suffice.
The module that I will attempt to load:
App.User = class {
constructor(name) {
this._name = name;
}
show() {
console.log(`Hello, I am ${this._name}.`);
}
}
The web page and script causing the problem:
<!DOCTYPE HTML>
<html>
<head>
<title>Dynamic Script Loading</title>
</head>
<body>
<p> A test for dynamic script loading</p>
<script>
App = {};
function loadScript(url) {
console.log(`loadScript: loading ${url}`);
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.type = 'text/javascript';
script.async = false;
script.src = url;
script.onload = () => {
console.log(`loadScript: loaded ${url}`);
resolve(script);
}
script.onerror = () => reject(new Error("Script load error: " + url));
document.body.appendChild(script);
console.log(`loadScript: loading ${url}`);
});
}
var hdlApp = {
get: function(obj, prop) {
if (prop in obj) {
console.log(`App has property ${prop}`);
return obj[prop];
} else {
console.log(`App does NOT have property ${prop}`);
loadScript(`${prop}.js`).then(
val => {
console.log('THEN');
return obj[prop]
},
err => {
console.log('CATCH');
return undefined;
}
);
}
}
}
window.App = new Proxy({}, hdlApp);
function test() {
console.log('First test');
u1 = new App.User('Fred');
u1.show();
}
</script>
</body>
</html>
On the first test, the new App.User
gets executed before the script has fully loaded. On a second attempt the script has fully loaded & compiled so it works. Which proves that the Proxy get() part is fine. I just don't know how to delay the constructor invocation until the script is fully loaded.