javascript - 如何在网页初始化之前获取一些文本文件(=>同步)
问题描述
我真的想做简单的事情——从磁盘/服务器加载一些glsl片段着色器,然后初始化 WebGL 网页。我真的不是网络程序员,通常我更喜欢用 C++ 编写着色器和 opengl。如果没有 WebGL,我永远不会使用 javascript。我没有意识到在 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
!因为在我下载这些文件之前,甚至无法初始化 GUI。
我知道有时非阻塞和异步操作很有用,尤其是当您想要制作响应式网页时。但有时不是,有时你真的想等到工作完成,选择应该在程序员身上。
解决方案
请告诉我如何通过阻止 GUI 来做到这一点!
使用XMLHttpRequest
which 支持同步模式,而不是fetch
.
但实际上你不应该这样做,它基本上已被弃用。了解如何为 Web 采用异步编程 :-) 实际上你非常接近。异步但完全顺序的代码看起来像这样 - 避免 promise 结果的全局变量:
<script>
async function loadTextfile(path) {
var response = await fetch(path);
return response.text();
}
async function loadPage() {
var str_Primitives = await loadTextfile('Primitives.glslf');
var str_RayTracer = await loadTextfile('RayTracer.glslf');
init_GLSLScreen(str_Primitives, str_RayTracer);
}
loadPage().catch(err => { console.error(err); });
</script>
现在,您可以通过同时加载两个文件来非常轻松地提高性能 - 只需更改为
async function loadPage() {
var [str_Primitives, str_RayTracer] = await Promise.all([
loadTextfile('Primitives.glslf'),
loadTextfile('RayTracer.glslf'),
]);
init_GLSLScreen(str_Primitives, str_RayTracer);
}
推荐阅读
- spring - 由于没有可见的构造函数,Spring Data Unit Test 无法实例化 EntityManagerFactory
- r - 使用包含换行符/回车符的名称重命名列
- multithreading - 微服务架构中的分布式锁
- php - 如何在没有分页的情况下获取api中的所有数据
- regex - 正则表达式:仅在不以单词开头时才替换短语
- spring - java.lang.IllegalStateException:需要 UserDetailsService。使用自定义提供程序
- r - 有没有办法优化这段代码,因为这需要几个小时才能执行
- python - Windows 10 上的任务计划程序不再工作
- kendo-ui - Kendo(Telerik) 不适用于 ASP .Net Core MVC 中的区域
- google-app-engine - 为什么我的谷歌应用引擎有域名'my-project.df.r.appspot.com'?