I am trying to deserialise a JSON object which has a type
key whose value is a string; if the type is "a", the object class is defined in "a.js" and this file contains an initialisation function a_init
. There may be a subobjects
key whose value is an array of objects. If so, these nested objects should be processed in the same way.
The code I have looks like this:
var files = [];
function load(obj) {
if (!!obj["type"]) {
let type = obj.type;
let subobjects = obj.subobjects;
let promise = new Promise(function(resolve) {
let script = document.createElement("script");
script.setAttribute("src", type + ".js");
script.addEventListener("load",resolve);
document.head.appendChild(script);
});
promise.then(function() {
if (!files.includes(type)) {
files.push(type);
if (subobjects instanceof Array) {
for (element of subobjects) {
load(element);
}
}
let func = window[type + "_init"];
if (typeof(func) =="function") {
func(obj);
}
}
});
}
}
For an object like this:
{ "type": "a",
"data": "foo",
"subobjects": [
{ "type": "b",
"data": "1"
}
]
}
the output is:
This is A
This is B
(The functions a_init
and b_init
just display a message for testing purposes.)
My problem is that I would like the subobjects to be initialized before the outer object, so b_init
would complete before a_init
to give this output:
This is B
This is A
but of course the nested call to load
just creates a new promise and then completes before the new promise does.
Is there any way to enforce synchronicity here to control the order of events?
You should convert your load
function to async
and inside it await
for the promise and also for the recursive calls to finish.
var files = [];
// using an async function here so that we can
// use await inside it, but also so that we can
// await the whole function (it is recursively called
// and we want the recursions to fully complete before
// continuing)
async function load(obj) {
if (!!obj["type"]) {
let type = obj.type;
let subobjects = obj.subobjects;
const promise = new Promise(function(resolve) {
let script = document.createElement("script");
script.setAttribute("src", type + ".js");
script.addEventListener("load", resolve);
document.head.appendChild(script);
});
await promise; // wait for the script to be loaded
if (!files.includes(type)) {
files.push(type);
if (subobjects instanceof Array) {
for (element of subobjects) {
// await for the nested object to completely run
// before continuing. This will go deep first
await load(element);
}
}
let func = window[type + "_init"];
// we reach this place only after all nested objects
// completed.
if (typeof(func) == "function") {
func(obj);
}
}
}
}