Я действительно хочу сделать простую вещь - загрузить несколько glsl фрагментных шейдеров с диска / сервера, а затем инициализировать WebGL-страницу. Я действительно не веб-программист, обычно я предпочитаю программировать шейдеры и opengl на C ++. Я бы никогда не положил руки на javascript, если бы не было WebGL. Я не осознавал, насколько сложно это было просто загрузить файл в javascript. Тогда кто-нибудь из переполнения стека рекомендует использовать fetch API , что кажется довольно удобным. Поэтому я попытался так:
// somewhere in HTML body far 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>
Проблема в том, что fetch
- это какая-то асинхронная фигня, поэтому init_GLSLScreen(str_Primitives, str_RayTracer)
выполняется до загрузки шейдеров => Выдает исключение, например cannot compile shaders and stuff ...
. Я действительно не хочу увлекаться этим асинхронным бизнесом, и Я хочу вернуться - к приличному синхронному программированию - как можно быстрее . потому что 1) отладка асинхронных вещей - ад, и 2) потому что программе действительно нечего делать, пока не загрузятся шейдеры.
Кажется, нет простого способа синхронизировать асинхронные и синхронные вызовы в javascript (что странно - на каждом параллельном языке программирования, который я знаю, у вас есть точки синхронизации). Нет ничего похожего на wait_to_resolve
, есть просто await , который (несмотря на то, что предполагает название) на самом деле ничего не ждет. Это только продвигает проблему дальше, заставляя вас также выполнять функцию оболочки async
.
Я могу заставить его работать следующим образом:
<script>
var str_RayTracer = "//RayTracer";
var str_Primitives = "//Primitives";
function initThis(txt){
// for some reason 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; // for some reason I must return something
}
loadPage().then( txt => initThis(txt) );
//loadPage().then( initThis() ); // doesn't seem to work
</script>
Но мне это не нравится, так как инициализация является последовательной операцией. Я не понимаю, почему я не могу написать нормальный последовательный код, и вместо этого должен цеплять обратные вызовы, как это. Это похоже на написание последовательной программы в обратном направлении.
Я пытался прочитать все потоки об этой проблеме при переполнении стека (например, 1 2 ), и это не очень полезноответ. Есть просто «О, мы здесь этого не делаем» мем . Лучше всего выражается здесь: Как мне вернуть ответ от асинхронного вызова?
Везде написано что-то вроде There is no way how to do it without blocking GUI
. Ок, и что? Подскажите как это сделать with blocking the GUI
, пожалуйста! Поскольку графический интерфейс пользователя не может быть даже инициализирован до тех пор, пока я не загружу эти файлы.
Я понимаю, что иногда неблокирующие и асинхронные операции полезны, особенно когда вы хотите сделать отзывчивую веб-страницу. Но иногда нет, иногда вы действительно хотите подождать, пока работа не будет выполнена, и выбор должен быть за программистом.