我通过调用许多异步加载资源的方法来初始化JS应用程序,每个方法都取决于先前的方法。我的直观解决方案是将调用嵌套在回调函数(cba,cbb,cbc,cbd)中,在成功完成以下操作(LoadA,LoadB,LoadC,LoadD)之后分别从LoadA,LoadB,LoadC,LoadD的内部调用beeing:
app.LoadA( function cba() {
app.LoadB( function cbb() {
....
app.LoadC( function cbc() {
...
app.LoadD( function cbd() {
...
} );
} );
} );
} );
LoadA( cb )
{
let url = '.........'; // just an url
let req = new XMLHttpRequest();
req.open('GET', url, true);
req.responseType = 'arraybuffer';
let lh = this;
req.onload = function ol(event)
{
let arrayBuffer = req.response;
let loadedObject = Convert( arrayBuffer, ......... );
cb( loadedObject ); // call, if successed!
}
req.send(null);
}
....
LoadA返回时不加载对象,因此LoadB必须等待,直到LoadA的嵌入式onload函数调用回调cb,依此类推。
我不喜欢这种嵌套解决方案,因为很难对其进行概述和维护。
我的问题是:是否有另一种(专注于“快乐之路”,更好,更短,更容易混淆,更易于理解和维护)实现相同结果的可能性?
最佳答案
为了避免回调地狱,您需要使用Promises。
如果loadA, ..., loadN
函数返回promise,则只需在每个命令之后依次调用.then()
。
loadA().then(function() {
loadB().then(function() {
loadC().then(...
});
});
现在重要的是要记住
.then()
返回一个Promise,该Promise将使用其参数的值进行解析。因此,如果
loadA
和loadB
都返回Promises,则可以像这样将它们链接起来:loadA().then(function() {
return loadB();
).then(...)
这等效于:
loadA().then(loadB).then(loadC).then(...)
简单得多!
如果您的函数没有返回Promise,则需要使用辅助函数将它们包装在其中。
function wrapInsidePromise(f) {
return new Promise(function(resolve, reject) {
f(function() {
resolve();
});
});
}
var pLoadA = wrapInsidePromise(app.loadA);
var pLoadB = wrapInsidePromise(app.loadB);
...
pLoadA().then(pLoadB).then(...);
此外,在ES6中,您可以使用
async/await
,让您以异步方式使用Promises。async function() {
await loadA();
await loadB();
...
let finalResult = await loadN();
...
}