我通过调用许多异步加载资源的方法来初始化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将使用其参数的值进行解析。

因此,如果loadAloadB都返回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();
  ...
}

08-08 07:31