Javascript WebGL:资源加载程序中的回调地狱
请帮我处理我产生的垃圾:Javascript WebGL:资源加载程序中的回调地狱,javascript,callback,Javascript,Callback,请帮我处理我产生的垃圾: Program.prototype.init = function() { loadText('../res/shaders/blinnPhong-shader.vsh', function (vshErr, vshText) { if (vshErr) { alert('Fatal error loading vertex shader.'); console.error(vshErr); } else {
Program.prototype.init = function()
{
loadText('../res/shaders/blinnPhong-shader.vsh', function (vshErr, vshText) {
if (vshErr) {
alert('Fatal error loading vertex shader.');
console.error(vshErr);
} else {
loadText('../res/shaders/blinnPhong-shader.fsh', function (fshErr, fshText) {
if (fshErr) {
alert('Fatal error loading fragment shader.');
console.error(fshErr);
} else {
loadJSON('../res/models/dragon.json', function (modelErr, modelObj) {
if (modelErr) {
alert('Fatal error loading model.');
console.error(modelErr);
} else {
loadImage('../res/textures/susanTexture.png', function (imgErr, img) {
if (imgErr) {
alert('Fatal error loading texture.');
console(imgErr);
} else {
this.run = true;
RunProgram(vshText, fshText, img, modelObj);
}
});
}
});
}
});
}
});
};
我的实际目标是抽象WebGL程序的资源加载过程。
这意味着未来将有网格、纹理、着色器阵列,我希望能够连接资源之间的某些依赖关系。例如:我想创建两个游戏对象1和2。一个使用着色器并从网格加载,但没有纹理,而两个使用与一个相同的着色器,但使用自己的网格,并且还需要纹理。我可以使用什么原则来实现在JavaScript中构建这些依赖关系(异步加载等等)
编辑:
这段代码发生了以下情况:我暂时保留了回调。但是,此方法是Singleton对象的一部分。我编辑了代码,因为在最后一种情况下,我将程序的标志设置为true。我在main中保留程序对象的全局引用。但是,由于回调,引用以某种方式丢失,全局引用将其标志保持为false,因此永远不会到达主循环。这显然是回调的问题,因为当我在嵌套回调之外调用“this.run=true”时会设置该标志。有什么建议吗?你可以用承诺来实现这一点。使用该模块,您可以将loadText转换为带有promiseifyAll(模块loadText来自)的promiseifyAll函数,或者如果该模块是您的模块,您可以使其返回一个
新的promise(函数(解析、拒绝){})
使用承诺,您可以创建一个包含所有要运行的承诺和承诺的数组。all([loadText('shader')、loadText(“其他着色器”)、…)
你可以为此使用承诺。使用该模块,您可以将loadText转换为带有promiseifyAll(模块loadText来自)的promiseifyAll函数,或者如果该模块是您的模块,您可以使其返回一个
新的promise(函数(解析、拒绝){})
使用承诺,您可以创建一个包含所有要运行的承诺和承诺的数组。all([loadText('shader')、loadText(“其他着色器”)、…)
使用现代API(如,和糖),您的代码可以变成:
Program.prototype.init = function () {
return Promise.all(
fetch('../res/shaders/blinnPhong-shader.vsh').then(r=>r.text()),
fetch('../res/shaders/blinnPhong-shader.fsh').then(r=>r.text()),
fetch('../res/models/dragon.json').then(r=>r.json()),
new Promise(function (resolve,reject) {
var i = new Image();
i.onload = () => resolve(i);
i.onerror = () => reject('Error loading image '+i.src);
i.src = '../res/textures/susanTexture.png';
})
)
.then(RunProgram);
}
您可以通过使用ES2017的相关功能(如/或放弃箭头函数并使用无缝多边形填充实现承诺和获取)来进一步提高兼容性。对于一些简单的请求缓存,请使用wrap-fetch:
const fetchCache = Object.create(null);
function fetchCached (url) {
if (fetchCache[url])
return Promise.resolve(fetchCache[url]);
return fetch.apply(null,arguments).then(r=>fetchCache[url]=r);
}
请注意,您希望您的资源是唯一的,因此上面提到的缓存仍然需要在其上添加另一层实际的GPU资源缓存,您不希望使用相同的着色器代码创建多个着色器程序,或者使用相同的顶点数据创建阵列缓冲区
关于如何管理依赖关系的实际核心问题过于宽泛/特定于应用程序,因此在此无法回答。关于在这种环境中管理异步特性,我看到两种选择:
Program.prototype.init = function () {
return Promise.all(
fetch('../res/shaders/blinnPhong-shader.vsh').then(r=>r.text()),
fetch('../res/shaders/blinnPhong-shader.fsh').then(r=>r.text()),
fetch('../res/models/dragon.json').then(r=>r.json()),
new Promise(function (resolve,reject) {
var i = new Image();
i.onload = () => resolve(i);
i.onerror = () => reject('Error loading image '+i.src);
i.src = '../res/textures/susanTexture.png';
})
)
.then(RunProgram);
}
您可以通过使用ES2017的相关功能(如/或放弃箭头函数并使用无缝多边形填充实现承诺和获取)来进一步提高兼容性。对于一些简单的请求缓存,请使用wrap-fetch:
const fetchCache = Object.create(null);
function fetchCached (url) {
if (fetchCache[url])
return Promise.resolve(fetchCache[url]);
return fetch.apply(null,arguments).then(r=>fetchCache[url]=r);
}
请注意,您希望您的资源是唯一的,因此上面提到的缓存仍然需要在其上添加另一层实际的GPU资源缓存,您不希望使用相同的着色器代码创建多个着色器程序,或者使用相同的顶点数据创建阵列缓冲区
关于如何管理依赖关系的实际核心问题过于宽泛/特定于应用程序,因此在此无法回答。关于在这种环境中管理异步特性,我看到两种选择:
这两种方法各有优缺点,但通常我会推荐第一种方法。这是可行的,它使用了最新的带有“sugars”的现代API,但代码仍然比通常的回调更难阅读。然而,这不是你的错,这是Javascrit的设计方式。@AnHauntingGhostAsPromise这怎么会“更不可读”?您节省了大量的垂直和水平空间。另外,这段代码也不全是糖分,它并行运行请求,而原始代码按顺序执行它们。除此之外,这段代码使您能够在一个位置处理所有错误,同时还允许您通过将拒绝处理程序附加到单个请求来实现回退和单个错误处理。代码的可读性不是通过文本在屏幕上所占的垂直和水平空间来衡量的,而是取决于文本如何易于查看,了解每个步骤、函数调用等的基本逻辑:谁做什么,谁调用谁,按什么顺序,等等。例如,它在调试上下文中有自己的实用程序。是的,您可以编写如下代码:
this.method(obj.func(函数(foo){return(foo>bar)?true:false;}))
但是,这是不可读的。您编写的内容,即使是有效的Javascript,也接近于所谓的“意大利面代码”,但Javascript在结构上推动您朝着这个方向前进。通过承诺,他们进一步推动了ce概念。承诺只允许您压缩代码,可能在没有额外自定义对象的情况下按顺序排序(承诺是对象:构建成本、内存分配等),但由于奇怪的语法混合,它们让事情变得更加难以遵循:代码看起来“必须”,但实际上是“异步”解释的。除了Javascript,我从未见过如此糟糕的t