美文网首页
JavaScript 异步操作里的嵌套回调函数

JavaScript 异步操作里的嵌套回调函数

作者: 华山令狐冲 | 来源:发表于2022-08-12 13:15 被阅读0次

嵌套回调函数经常用在两个逻辑上具有先后顺序的异步操作场景中。

思考下面的问题:我们如何按顺序加载两个脚本?

自然的解决方案是将第二个 loadScript 调用放在回调中,如下所示:

loadScript('/my/script.js', function(script) {

  alert(`Cool, the ${script.src} is loaded, let's load one more`);

  loadScript('/my/script2.js', function(script) {
    alert(`Cool, the second script is loaded`);
  });

});

外层 loadScript 完成后,回调启动内层的 loadScript 调用。

如果我们想要顺序加载更多的脚本,该怎么办?

loadScript('/my/script.js', function(script) {

  loadScript('/my/script2.js', function(script) {

    loadScript('/my/script3.js', function(script) {
      // ...continue after all scripts are loaded
    });

  });

});

关于回调参数的出错处理

在上面的例子中,我们没有考虑错误。 如果脚本加载失败怎么办? 我们的回调应该能够对此做出反应。

这是一个改进的 loadScript 版本,可以跟踪加载错误:

function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;

  script.onload = () => callback(null, script);
  script.onerror = () => callback(new Error(`Script load error for ${src}`));

  document.head.append(script);
}

它调用 callback(null, script) 成功加载,否则调用 callback(error)。

消费代码:

loadScript('/my/script.js', function(error, script) {
  if (error) {
    // handle error
  } else {
    // script loaded successfully
  }
});

我们用于 loadScript 的方法实际上很常见。 它被称为“错误优先回调(error-first callback)”风格。

约定是:

如果发生错误,回调的第一个参数是为错误保留的。 然后回调(错误)被调用。

第二个参数(如果需要,还有下一个参数)用于成功的结果。 然后调用 callback(null, result1, result2…)。

因此,单个回调函数用于报告错误和传回结果。

Pyramid of Doom

乍一看,嵌套回调函数看起来像是一种可行的异步编码方法。 确实如此。 对于一个或两个嵌套调用,其复杂度尚在编程人员能够掌控的范围内。

但是对于一个接一个的多个异步操作,我们会有这样的代码:

loadScript('1.js', function(error, script) {

  if (error) {
    handleError(error);
  } else {
    // ...
    loadScript('2.js', function(error, script) {
      if (error) {
        handleError(error);
      } else {
        // ...
        loadScript('3.js', function(error, script) {
          if (error) {
            handleError(error);
          } else {
            // ...continue after all scripts are loaded (*)
          }
        });

      }
    });
  }
});

随着调用变得更加嵌套,代码变得更深并且越来越难以管理,特别是如果我们有真正的代码而不是......可能包括更多的循环、条件语句等。

这有时被称为 回调地狱末日金字塔

嵌套调用的“金字塔”随着每个异步操作而向右增长。 很快它就失去了控制。

我们可以把每个匿名回调函数,改写成为由名称的标准函数,来部分程度的规避回调地狱问题:

loadScript('1.js', step1);

function step1(error, script) {
  if (error) {
    handleError(error);
  } else {
    // ...
    loadScript('2.js', step2);
  }
}

function step2(error, script) {
  if (error) {
    handleError(error);
  } else {
    // ...
    loadScript('3.js', step3);
  }
}

function step3(error, script) {
  if (error) {
    handleError(error);
  } else {
    // ...continue after all scripts are loaded (*)
  }
}

我们使用 JavaScript 提供的 promise,可以从根本上规避回调地狱问题。

相关文章

  • JavaScript 异步操作里的嵌套回调函数

    嵌套回调函数经常用在两个逻辑上具有先后顺序的异步操作场景中。 思考下面的问题:我们如何按顺序加载两个脚本? 自然的...

  • Async/Await 函数用法

    JavaScript编程异步操作解决方案:回调函数 => Promise对象 => Generator函数 => ...

  • Promise

    1. 异步回调 1.1 回调地狱 在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的回调地...

  • Promise、class

    1、promise是异步操作的一种解决方案,一般用来解决层层嵌套的回调函数(回调地狱) 2、三个状态及then函数...

  • 14.回调地狱与 Promise

    回调地狱 为了保证异步代码的执行顺序,将异步代码嵌套到回调函数中,当异步的方法多了,就会产生回调地狱(callba...

  • 《全栈工程师修炼指南》学习笔记 15

    异步编程 JavaScript 回调函数容易引起回调地狱 后来有了 Promise,可以将回调函数以 then 的...

  • JavaScript 异步回调 / Promise/A规范

    Javascript里异步编程逐渐被大家接受,先前大家一般通过回调嵌套,setTimeout、setInterva...

  • 《Promise》

    1、初识Promise Promise 是异步操作的一种解决方案Promise 一般用来解决层层嵌套的回调函数(回...

  • 含答案的面试题总结

    1. 说说JavaScript中有哪些异步编程方式? 1. 回调函数 回调函数是异步编程的基本方法。其优点是易编写...

  • ES6:理解Promise

    1、Promise 在Promise以前,在需要多个异步操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是...

网友评论

      本文标题:JavaScript 异步操作里的嵌套回调函数

      本文链接:https://www.haomeiwen.com/subject/iuixgrtx.html