I have a simple task at hand that I really want to accomplish - loading some glsl fragment shaders from the disk or server, and then initializing a WebGL web page. Web programming is not my forte; I usually prefer working on shaders and OpenGL in C++. If it weren't for WebGL, I wouldn't even bother with JavaScript. Little did I know how challenging it would be just to load a file in JavaScript. Then someone on Stack Overflow recommended using the fetch API, which seemed quite convenient. So, I gave it a shot:
// somewhere in HTML body far away
<script>
var str_RayTracer = "//RayTracer";
var str_Primitives = "//Primitives";
fetch('RayTracer.glslf') .then(response => response.text()).then(text => str_RayTracer = text );
fetch('Primitives.glslf').then(response => response.text()).then(text => str_Primitives = text );
init_GLSLScreen(str_Primitives, str_RayTracer);
</script>
The issue here is that fetch is asynchronous, so init_GLSLScreen(str_Primitives, str_RayTracer) executes before the shaders are loaded, resulting in an exception like "cannot compile shaders and stuff...". I don't want to deal with this asynchronous complexity; I want to go back to simple synchronous programming as quickly as possible. Debugging asynchronous code is a nightmare, and the program has nothing else to do until the shaders are loaded.
It seems there's no straightforward way to synchronize asynchronous and synchronous calls in JavaScript. There's no wait_to_resolve concept; we only have await, which doesn't actually make you wait but instead pushes the problem onto wrapper functions that need to be marked async.
To work around this, I can do the following:
<script>
var str_RayTracer = "//RayTracer";
var str_Primitives = "//Primitives";
function initThis(txt){
// I must take `txt`, although I don't use it
init_GLSLScreen(str_Primitives, str_RayTracer);
}
async function loadPage(){
str_Primitives = await fetch('Primitives.glslf').then( r => r.text() );
str_RayTracer = await fetch('RayTracer.glslf' ).then( r => r.text() );
return 0; // I must return something for some reason
}
loadPage().then( txt => initThis(txt) );
//loadPage().then( initThis() ); // this doesn't seem to work
</script>
But I find this solution cumbersome because initialization is inherently a sequential operation. I believe I should be able to write normal sequential code without having to chain callback dependencies like this.
I've read through numerous threads on Stack Overflow addressing this issue, but there doesn't seem to be a satisfactory answer. It's mostly responses like "Oh, we don't do that here" accompanied by memes. The question of how to handle returning the response from an asynchronous call remains unanswered.
Everywhere I look, I see statements like "There's no way to do it without blocking the GUI." Okay, fine. But can someone please tell me how to do it while blocking the GUI? After all, the GUI can't even initialize until those files are downloaded.
I understand the benefits of non-blocking and asynchronous operations, especially when aiming for a responsive web page. However, there are times when waiting for a task to complete is necessary, and that choice should be left up to the programmer.