JavaScript异步编程方式多,区别是什么?

news/2025/2/23 8:45:49

在JavaScript中,常见的异步编程方式有回调函数、Promise、Generator函数和async/await,以下用大白话介绍它们的区别并给出代码示例:

回调函数

  • 概念:就是把一个函数当作参数传给另一个函数,等那个函数完成任务后再调用这个作为参数的函数。就好像你让朋友帮你做件事,做完后让他打电话告诉你,这个打电话告诉你的动作就是回调函数。
  • 缺点:如果有多个异步操作相互依赖,回调函数会层层嵌套,形成“回调地狱”,代码可读性和维护性很差。
  • 代码示例
javascript">function getData(callback) {
    // 模拟异步操作,比如从服务器获取数据
    setTimeout(() => {
        const data = { name: '张三', age: 25 };
        callback(data);
    }, 1000);
}

getData((data) => {
    console.log('获取到的数据:', data);
});

Promise

  • 概念:可以理解为一个承诺,它表示一个异步操作最终会有一个结果,要么成功(resolved),要么失败(rejected)。它可以让异步操作的代码看起来更清晰,避免了一部分回调地狱的问题。
  • 优点:通过 .then().catch() 方法来处理成功和失败的情况,使得代码更易于阅读和维护,并且可以方便地进行链式调用。
  • 代码示例
javascript">function getData() {
    return new Promise((resolve, reject) => {
        // 模拟异步操作
        setTimeout(() => {
            const data = { name: '李四', age: 30 };
            resolve(data);
        }, 1000);
    });
}

getData()
   .then((data) => {
        console.log('获取到的数据:', data);
    })
   .catch((error) => {
        console.log('获取数据失败:', error);
    });

Generator函数

  • 概念:Generator函数是一种特殊的函数,它可以暂停和恢复执行。在函数内部可以使用 yield 关键字来暂停函数执行,返回一个值,等外部调用 next() 方法时再继续执行。它可以用来控制异步操作的流程,让异步操作看起来更像同步操作。
  • 优点:可以更精细地控制异步操作的流程,在异步操作较多且需要按顺序执行等复杂场景下有优势。
  • 代码示例
javascript">function* getDataGenerator() {
    // 模拟异步操作
    yield new Promise((resolve) => {
        setTimeout(() => {
            resolve({ name: '王五', age: 35 });
        }, 1000);
    });
}

const generator = getDataGenerator();
const promise = generator.next().value;
promise.then((data) => {
    console.log('获取到的数据:', data);
});

async/await

  • 概念:是基于Promise的一种更简洁的异步编程方式。async 函数用来定义一个异步函数,函数内部可以使用 await 关键字来暂停函数执行,等待一个Promise对象 resolve后再继续执行。它让异步代码看起来几乎和同步代码一样,大大提高了代码的可读性。
  • 优点:代码简洁、易读,非常适合处理多个异步操作按顺序执行的场景,能很好地替代Generator函数和Promise的链式调用。
  • 代码示例
javascript">async function getData() {
    // 模拟异步操作
    await new Promise((resolve) => {
        setTimeout(() => {
            resolve({ name: '赵六', age: 40 });
        }, 1000);
    });
    // 假设还有其他操作
    return { name: '赵六', age: 40 };
}

getData().then((data) => {
    console.log('获取到的数据:', data);
});

总体来说,回调函数是最基础的异步编程方式,但容易出现回调地狱;Promise解决了回调地狱的问题,让异步操作更易管理;Generator函数提供了更灵活的异步控制方式;async/await则是在Promise的基础上,让异步代码看起来更像同步代码,是目前比较推荐的异步编程方式。实际开发中,可以根据具体的场景和需求来选择合适的异步编程方式。

sync/await和Promise有什么关联和区别?

关联

async/awaitPromise 紧密相关,async/await 其实是建立在 Promise 之上的一种语法糖,它让使用 Promise 进行异步编程的代码看起来更简洁、更像同步代码。可以把 Promise 想象成是实现异步操作的基础工具,而 async/await 则是对这个工具进行了包装,让我们使用起来更加方便顺手。

区别

语法层面
  • Promise:使用 .then() 方法来处理 Promise 成功的结果,使用 .catch() 方法来处理 Promise 失败的情况,并且可以进行链式调用。代码结构上会有多层嵌套,当异步操作较多时,可能会让代码显得复杂。
  • async/await:使用 async 关键字定义一个异步函数,在函数内部使用 await 关键字来暂停函数的执行,等待一个 Promise 被解决(resolved)或被拒绝(rejected)。代码结构更接近同步代码,阅读和理解起来更加直观。
错误处理层面
  • Promise:错误处理主要依靠 .catch() 方法,需要在链式调用中合适的位置添加该方法来捕获错误。如果链式调用较长,可能会出现错误处理不够清晰的情况。
  • async/await:可以使用传统的 try...catch 语句来捕获和处理错误,这种方式和同步代码的错误处理方式一致,更加直观和方便。
代码可读性和编写难度层面
  • Promise:当异步操作逻辑较为复杂,需要多个 Promise 链式调用时,代码的嵌套层次会增多,可读性会降低,编写和维护的难度也会相应增加。
  • async/await:代码结构清晰,就像写同步代码一样,降低了编写和理解异步代码的难度,提高了代码的可读性和可维护性。

代码示例

使用 Promise
javascript">// 模拟一个异步操作,返回一个 Promise
function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;
            if (success) {
                resolve('数据获取成功');
            } else {
                reject('数据获取失败');
            }
        }, 1000);
    });
}

// 使用 Promise 的链式调用处理异步操作
fetchData()
  .then((data) => {
        console.log(data);
        return '处理后的数据';
    })
  .then((processedData) => {
        console.log(processedData);
    })
  .catch((error) => {
        console.error(error);
    });
使用 async/await
javascript">// 同样模拟一个异步操作,返回一个 Promise
function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;
            if (success) {
                resolve('数据获取成功');
            } else {
                reject('数据获取失败');
            }
        }, 1000);
    });
}

// 定义一个异步函数
async function getData() {
    try {
        // 使用 await 等待 Promise 解决
        const data = await fetchData();
        console.log(data);
        const processedData = '处理后的数据';
        console.log(processedData);
    } catch (error) {
        // 使用 try...catch 处理错误
        console.error(error);
    }
}

// 调用异步函数
getData();

从上述代码可以看出,async/await 让异步代码的结构更加清晰,错误处理也更加直观,而 Promise 的链式调用在处理复杂异步逻辑时可能会让代码显得繁琐。


http://www.niftyadmin.cn/n/5863210.html

相关文章

Spring MVC 框架学习笔记:从入门到精通的实战指南

目录 1. Spring MVC 概述 2. Spring MVC 项目搭建 3. Spring MVC 执行流程 4. Spring MVC RequestMapping 注解 5. Spring MVC 获取请求参数 6. Spring MVC 常见注解 7. Spring MVC 响应处理 8. Spring MVC SSM 整合 9. Spring MVC 作用域传参 10. Spring MVC 上传 1…

pytorch PIL对np和tensor 图像数据的显示

(显示图像) PIL可以显示np的图像数据,np是 whc的格式。 在np转换为tenser格式后会自动转换为cWH的格式,tenser再转回来时,依然是cwh格式 np.tranpose(1,2,0)可以将cwh格式转换为whc的格式,也…

线性回归 (Linear Regression)基础知识1

本章节主要介绍:回归任务简介、线性回归模型、回归任务的损失函数 *回归任务*机器学习的三要素线性回归线性回归模型 *数据分析*散点图*相关性系数矩阵 *拓展知识:相关性系数矩阵定义计算相关性系数矩阵示例应用 线性回归的损失函数回归任务目标函数&…

redis中的Lua脚本,redis的事务机制

lua脚本的特点 lua脚本可以操作redis数据库,并且脚本中的代码满足原子性,要么全部被执行,要么全部不执行 lua脚本的语法 脚本示例 lua脚本的草稿: 最终的lua脚本 lua脚本在java里调用的方法 RedisTemplete类里有一个方法&…

音视频入门基础:RTP专题(10)——FFmpeg源码中,解析RTP header的实现

一、引言 由《音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现》可以知道,FFmpeg接收RTP流时,其源码内部会调用rtp_read函数。而rtp_read函数内部会通过recvfrom函数接收基于UDP的RTP音视频数据。一般…

【每日一算法】二分查找

在图书馆,需要查找一本书。首先想到如何快速找到它? 书籍通常按顺序排列(字母顺序或字母数字顺序),这就是二分查找适用的场景。你可以快速排除一半的书籍,每次比较后再缩小范围,迅速定位目标书籍…

pytest下allure

import pytestdef test_case01():用例01~print(用例01)class Test_mokuai01:def test_case02(self):用例02~print(用例02)if __name____main__:#pytest.main([-vs,test_sample-2.py])pytest.main([-vs,test_sample-2.py,--allure-dir,./result2])#生成allure报告,参…

【超详细】神经网络的可视化解释

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…