JS:一篇文章带你搞懂什么是异步

前言

我们先来说说什么是异步,异步操作并不仅仅局限于编程和计算机科学领域,我们在日常生活中也经常会遇到异步的情况。我们用这几个有趣的例子来帮大家理解一下:

  1. 电子邮件通信: 发送电子邮件是一种异步操作。你发送了一封邮件之后,并不需要立即等待对方回复,而是可以继续进行其他活动。当对方准备好回复时,他们会发送回复。
  2. 邮寄信件: 将信件寄出后,并不会立即送达,而是需要一些时间。寄件人不需要等待信件到达目的地,而可以进行其他活动。
  3. 预约和会议: 安排预约或会议也是一种异步操作。当你预约或安排会议时,并不需要等待对方立即确认,而是可以进行其他安排。对方会在适当的时候回复或确认。
  4. 交通信号灯: 交通信号灯的变化是异步的。当你等待红灯变绿时,你并不需要一直停车等待,而可以进行其他事情,只有当信号变绿时才需要继续行驶。
  5. 购物: 在网上购物时,提交订单后并不需要立即等待商品送达。你可以继续进行其他活动,而在适当的时间收到商品。

异步

异步(Asynchronous)是指在不同步或不同时的时间执行任务或操作的方式。在编程和计算机科学领域中,异步通常用来描述一种处理事件和任务的机制,其中不需要等待一个操作完成,而是可以同时执行其他操作。

在同步编程中,程序的执行是按照顺序一步一步进行的,每个操作都需要等待上一个操作完成后才能执行。这可能导致程序在等待某些操作完成的同时处于空闲状态。

相比之下,在异步编程中,程序可以继续执行其他操作而不必等待某个操作完成。当异步操作完成时,通常通过回调函数、Promise对象或异步/等待(async/await)等机制来处理结果。这种方式有助于提高程序的响应性和效率,特别是在处理网络请求、文件操作或其他涉及等待时间的任务时。

JavaScript(JS)是一种异步编程语言。JavaScript最初设计为一种用于在浏览器中操作DOM(文档对象模型)的脚本语言,因此异步编程对于处理用户界面的交互、网络请求和其他事件至关重要。

我们先来看一个异步的例子:

假如我们去饭店吃饭时,我们点好了菜之后,厨师开始炒菜,那我们在厨师炒菜的时候一般会玩玩手机,刷刷抖音,而不是坐在那里一动不动等着厨师上菜

js 复制代码
function a (){ 
    setTimeout(function(){
         console.log('刷会抖音')
        },1000)
    }
    a()
    function b (){
         console.log("菜做完啦!")
    }
    b()

我们先来看看输出结果:

我们可以看到输出顺序为菜做完啦过了一秒钟之后再打印刷会抖音

这段代码涉及到异步执行的概念,主要是通过setTimeout函数创建了一个定时器,该定时器会在指定的时间间隔后执行回调函数。让我们一步一步解释这段代码:

js 复制代码
function a (){ 
    setTimeout(function(){
        console.log('刷会抖音');
    }, 1000);
}

这是一个函数 a,其中使用 setTimeout 函数创建了一个定时器。这个定时器会在 1000 毫秒(即1秒)后执行一个匿名函数,而这个匿名函数的内容是输出 '刷会抖音'

然后,你调用了函数 a

js 复制代码
a();

由于 setTimeout 是异步的,它会在后台计时,不会阻塞程序的执行。所以,调用 a 后,程序会立即继续往下执行,而不会等待定时器的回调执行。

接着,你有另一个函数 b

js 复制代码
function b (){
    console.log("菜做完啦!");
}

这个函数 b 用于输出信息 "菜做完啦!"

最后,你调用了函数 b

js 复制代码
b();

在整个程序执行过程中,b 函数会立即执行,而不会等待定时器的回调函数。因此,你可能会在控制台看到类似于以下的输出:

js 复制代码
菜做完啦!
刷会抖音

这是因为 b 函数会立即执行,而 a 函数中的定时器回调函数会在1秒后执行。这展示了异步执行的特性,使得程序能够继续执行而不必等待定时器完成。

那如果我们想要刷会抖音菜做完啦之前执行,可以做些什么呢?

回调函数

js 复制代码
function a(cb){
    setTimeout(() => { 
        console.log("刷会抖音");
        cb() 
    },1000)
}

function b(){ 
    setTimeout(() => {
        console.log("菜做完啦");
    }, 0);
}

  a(b)

这段代码包含两个函数 ab,并通过将函数 b 作为回调函数传递给函数 a 来展示异步操作和回调函数的概念。让我们一步一步解释:

js 复制代码
function a(cb) {
    setTimeout(() => { 
        console.log("刷会抖音");
        cb();
    }, 1000);
}

这是一个函数 a,它接受一个回调函数 cb 作为参数。在函数体内,使用 setTimeout 函数创建了一个定时器,它会在 1000 毫秒(即1秒)后执行一个匿名函数。这个匿名函数的内容包括输出 '刷会抖音' 和调用回调函数 cb

然后,你有另一个函数 b

js 复制代码
function b() { 
    setTimeout(() => {
        console.log("菜做完啦");
    }, 0);
}

这是另一个函数 b,它使用 setTimeout 创建了一个定时器,该定时器在 0 毫秒后执行一个匿名函数,输出 '菜做完啦'

最后,我们调用了函数 a,将函数 b 作为回调函数传递进去:

js 复制代码
a(b);

在这里,调用 a 会启动一个定时器,在 1 秒后执行 '刷会抖音' 并调用回调函数 cb,而 cb 此时指向函数 b。所以,即便函数 b 的定时器设置为0秒,它的执行会在函数 a 的定时器之后,但在整体执行上并没有造成延迟。

因此,我们会在控制台看到以下的输出:

js 复制代码
刷会抖音
菜做完啦

这展示了如何通过回调函数来管理异步操作的执行顺序。

回调地狱

回调地狱(Callback Hell)是指在异步编程中,多个嵌套的回调函数形成的代码结构复杂、难以理解和维护的情况。这通常发生在处理多个异步操作,其中一个操作的结果需要作为参数传递给另一个操作,依此类推。

以下是一个简单的例子,展示了回调地狱的情况:

js 复制代码
getDataFromServer(function (data) {
    process1(data, function (result1) {
        process2(result1, function (result2) {
            process3(result2, function (result3) {
                // More nested callbacks...
            });
        });
    });
});

在这个例子中,每个异步操作的结果都需要传递给下一个操作,导致代码缩进层次加深,可读性变差。这种结构会使代码难以维护,容易出现错误,并且不符合良好的代码风格。

在下一篇文章中我们会讲如何用更好的方式去处理异步

相关推荐
_.Switch18 分钟前
Python Web 架构设计与性能优化
开发语言·前端·数据库·后端·python·架构·log4j
libai20 分钟前
STM32 USB HOST CDC 驱动CH340
java·前端·stm32
南斯拉夫的铁托1 小时前
(PySpark)RDD实验实战——取最大数出现的次数
java·javascript·spark
Java搬砖组长1 小时前
html外部链接css怎么引用
前端
GoppViper1 小时前
uniapp js修改数组某个下标以外的所有值
开发语言·前端·javascript·前端框架·uni-app·前端开发
丶白泽1 小时前
重修设计模式-结构型-适配器模式
前端·设计模式·适配器模式
程序员小羊!1 小时前
UI自动化测试(python)Web端4.0
前端·python·ui
破z晓1 小时前
OpenLayers 开源的Web GIS引擎 - 地图初始化
前端·开源
好看资源平台1 小时前
JavaScript 数据可视化:前端开发的核心工具
开发语言·javascript·信息可视化
维生素C++2 小时前
【可变模板参数】
linux·服务器·c语言·前端·数据结构·c++·算法