说说JavaScript里的回调函数

823 阅读2分钟

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

计算机程序设计中,回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过参数函数传递到其它代码的,某一块可执行代码引用。——维基百科


问题示例

假如现在有这样一个动态加载脚本的函数

function loadScript(src) {
  // 创建一个 <script> 标签,并将其附加到页面
  // 这将使得具有给定 src 的脚本开始加载,并在加载完成后运行
  let script = document.createElement('script');
  script.src = src;
  document.head.append(script);
}

创建一个lodash.js文件为例

https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js

假如你想把lodash.js加载到页面,可以这样做

// 在给定路径下加载并执行脚本
loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js');

lodash.js中声明了函数_

image-20211122004559413

如果你在 loadScript(…) 调用后立即执行获取这个函数,会发现这个函数未定义

image-20211122004721505

这是因为脚本是“异步”调用的,也就是说,如果在 loadScript(…) 下面有任何其他代码,它们不会等到脚本加载完成才执行。所以这个时候你调用lodash.js里的函数_,会直接报错,因为此时函数还不存在。


解决方案

为了解决这个问题,我们可以添加一个callback 函数作为 loadScript 的第二个参数,该函数应在脚本加载完成时执行。

改进:

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

  script.onload = () => callback(script);  //关键代码

  document.head.append(script);
}

现在,如果想要调用script.js文件中的方法,可以把方法写在回调函数中,因为回调函数会在在脚本加载完成后才执行。

loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => {
  console.log(`script ${script.src} is loaded`);
  console.log('脚本中声明的函数', _ ); 
});

运行结果:

image-20211122005311125

在JavaScript中被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。

改进

上面我们并没有考虑出现 error 的情况。比如脚本加载失败了。所以我们需要改进一下,新增加载错误的处理

image-20211122010005965

这个时候,如果加载成功,则调用 callback(null, script),反之调用 callback(error)

image-20211122005920244


新的问题

当我们只有一个回调的时候,还没有什么,但是当回调太多时,代码就会像这样变得杂乱无章,这也就是常说的回调地狱。

image-20211122010427915

所以很明显我们还需要有更好的方法来解决这个问题,其中较好的方法之一就是后面将会说到的promise

参考资料:

Callback (computer programming)

Introduction: callbacks

MDN Callback function


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 一起来看看JS的原型继承

👉 JS中的getter和setter你会用吗?

👉 深入理解ES6箭头对象

👉 JS的装饰器模式实例分析