异步系列:回调 简介 异步是什么意思?为什么会发生这种情况? 异步代码实践 进入流程 编写高阶函数 结论

2025-06-07

异步系列:回调

介绍

Async 是什么意思?

为什么会发生这种情况?

异步代码实际应用

进入心流

编写高阶函数

结论

介绍

JavaScript 初学者最容易犯的一个错误就是异步编程。本系列将揭秘 JavaScript 中异步编程的神秘面纱。

Async 是什么意思?

我们编写的大多数代码都是顺序或同步执行的。也就是说,先执行第 1 行,然后执行第 2 行,最后执行第 3 行。

例如,以下都是同步函数调用。一次只能执行其中一个。如果你正在洗澡,那么你可以放心地认为唤醒任务已经完全完成。

wakeup()
eatBreakfast()
takeShower()
Enter fullscreen mode Exit fullscreen mode

然而,在 JavaScript 中,一些函数调用是并发执行的。这意味着浏览器实际上会在它们之间切换,使它们看起来像是同时进行的。

例如:从早上醒来的那一刻起,你开始观察世界。然后,你可能开始活动,并在某个时刻开始进食。你甚至可能同时进行这三项!注意,即使你在进食之前就开始观察世界,进食任务也会在观察之前完成。本质上,这就是异步函数调用的行为方式。

see()
move()
eat()
Enter fullscreen mode Exit fullscreen mode

因此,一系列异步函数调用的执行结束顺序可能与启动顺序不同。对于需要特定顺序的新程序员来说,这常常会让他们感到沮丧。

为什么会发生这种情况?

虽然这不是一个硬性要求,但如果你想了解为什么会发生这种情况,你可以看看我关于 JavaScript 运行时的帖子。

异步代码实际应用

我有三个异步函数 printBlue/Green/Red。它们都会并发执行,但各自的执行时间不同。Green 最快,Red 最快,Blue 最慢。所以,如果像这样调用它们:

printBlue("Blue");
printGreen("Green");
printRed("Red");
Enter fullscreen mode Exit fullscreen mode

输出:

图像

输出为:绿色、红色、蓝色。下图直观地展示了这些函数的执行时间。

图像

进入心流

由于它们各自的执行速度,这些函数的完成顺序与它们被调用的顺序不同,即打印“绿色”、“红色”然后“蓝色”。但是,我们想要打印“蓝色”、“绿色”然后“红色”,我们该如何解决这个问题?

在编程中,控制流是指强制执行语句顺序的概念。在 JavaScript 中,我们让开发者实现这一点的一种方法是让异步函数接受回调函数

回调函数是我们传递给另一个函数 A(通常是异步的)的函数 C,这样只有当 A 的主要工作完成时,A 才会执行 C。

由于函数 A 具有另一个函数作为参数,因此它也被称为高阶函数。

幸运的是,我们的打印函数确实接受回调函数,所以我们可以创建一些辅助函数来实现我们想要的打印功能。然后,将辅助函数作为回调函数传递。

//helper function 1
function doPrintRed(){
  //calls print red with our desired parameter
  printRed('Red');
}

//helper function 2
function doPrintGreenRed(){
  //calls printGreen with our desired parameter 
  //then passes doPrintRed as a callback
  printGreen('Green', doPrintRed);
}

//call printBlue then passes do doPrintGreenRed as a callback
printBlue("Blue", doPrintGreenRed);
Enter fullscreen mode Exit fullscreen mode

然而,这太长了。由于除了将辅助函数作为回调传递之外,我们没有任何用处,因此我们可以改用匿名函数

匿名函数是没有名字的函数定义,可以在任何可以引用函数的地方编写。例如,我们可以在 doPrintGreen 中提供一个匿名函数,而不是编写 doPrintRed。

//helper function 2
function doPrintGreenRed(){
  //calls printGreen with our desired parameter 
  //replace reference to doPrintRed with an anonymous function
  printGreen('Green', function(){
      //calls print red with our desired parameter
      printRed('Red');
  });
}

//call printBlue then passes do doPrintGreenRed as a callback
printBlue("Blue", doPrintGreenRed);

Enter fullscreen mode Exit fullscreen mode

我们将 doPrintRed 的代码移到了一个匿名函数中,并将其作为回调传递给 printGreen。因此,printGreen 的第二个参数被称为匿名回调函数

然后,您可以重复 doPrintGreenRed 的过程以实现以下目标。

//replace reference to doPrintGreenRed with an anonymous function
printBlue("Blue", function(){
   //calls printGreen with our desired parameter 
   printGreen("Green", function(){
     //calls print red with our desired parameter
     printRed("Red");
   });
});
Enter fullscreen mode Exit fullscreen mode

传递的回调函数 printBlue() 调用 printGreen()。printGreen() 反过来也接收一个回调函数,然后该回调函数调用 printRed()。printBlue/Green/Red 的设计方式使得它们接收的回调仅在打印到屏幕后执行。

这是输出:

图像

现在的执行看起来是这样的。

图像

这是因为最内层函数必须等待外部函数执行,而外部函数必须等待另一个外部函数开始执行。

编写高阶函数

异步函数的作者负责设计该函数以接受回调,使用适当的值执行回调并通过文档进行解释。

下面是接收回调函数的高阶加法函数的简单实现。

function add(a, b, callback){//allow a callback to be passed
  let answer = a + b;//perform calculation
  callback(answer);//pass the output of the calculation to the callback
}

add(4, 5, function(result){
 console.log("The result is", result);
});//Output: The result is 9

Enter fullscreen mode Exit fullscreen mode

函数 add() 计算总和,并将结果传递给传递给 add() 的函数参数。高阶函数(例如 add())可能不会返回结果,而是要求将结果传递给一个函数。

示例代码可在此REPL中找到,因此您可以自己尝试一下。

结论

异步 JavaScript 的介绍到此结束。许多 JavaScript API 都是异步的,包括 fetch()。掌握这个基本概念将对您的学习之旅大有裨益。

文章来源:https://dev.to/snickdx/the-async-series-callbacks-5dc0
PREV
前端漫游指南:Web API 简介 Web Sockets Web Workers Service Workers 语音识别设备传感器文件系统访问总结更多关于 Web API 的内容
NEXT
10 个最佳 Web 开发堆栈