首页 > 编程语言 >JS异步编程精通之路(一):Callback、Promise、Async/Await 和 Observable 深度对比

JS异步编程精通之路(一):Callback、Promise、Async/Await 和 Observable 深度对比

时间:2024-10-14 11:46:31浏览次数:9  
标签:Observable 异步 处理 Await JS Promise Async Data

在现代 JavaScript 编程中,异步操作是常见且必不可少的部分。处理异步的方式多种多样,其中最常见的有 Callback、Promise、Async/Await,以及近年来随着响应式编程(Reactive Programming)理念兴起的 Observable。本文将对这几种异步处理方式进行对比,帮助你理解它们各自的优缺点,以及在实际开发中如何选择合适的方式。

本文将介绍一种非常适合js这种基于事件的设计模式-观察者模式,以及尤其衍生的响应式编程。因为tc39到WICG等变化,导致迟迟未能推荐 Obserbvable提案最新 老版tc39提案,至于这些团体事件我们不管,因为js是很灵活的,有一个叫做 rxjs 的库较好的实现了这个模式,而且出到了第七个大版本。个人也使用其超过三年半
后续的一些内容,尤其是较为复杂的业务中,往往需要用到它来简化异步控制流,所以这里先介绍和对比集中场景的解决方案

1. Callback

概述

Callback 是 JavaScript 中最原始的异步编程方式。通过将函数作为参数传递给另一个函数,异步操作完成时,调用传入的回调函数来执行后续逻辑。通常会在事件处理、定时器或网络请求中使用。

示例

function fetchData(callback) {
    setTimeout(() => {
        callback(null, "Data fetched");
    }, 1000);
}

fetchData((err, result) => {
    if (err) {
        console.error(err);
    } else {
        console.log(result);  // "Data fetched"
    }
});

优点

  • 语法简单,容易理解。
  • 可以直接处理多个并发异步操作。

缺点

  • 容易导致回调地狱(Callback Hell):当多个异步操作需要按顺序执行时,回调函数嵌套过深,代码难以维护和阅读。
  • 错误处理复杂:回调函数中每次都需要手动处理错误,容易遗漏。

2. Promise

概述

Promise 是为了解决 Callback 方式中代码难以维护的问题而引入的。它表示一个异步操作的最终完成(或失败),并返回一个结果。通过 .then().catch() 来链式处理异步任务和错误。

示例

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Data fetched");
        }, 1000);
    });
}

fetchData()
    .then(result => console.log(result))  // "Data fetched"
    .catch(err => console.error(err));

优点

  • 链式结构清晰,避免了回调地狱,异步流程更具可读性。
  • 内建错误处理机制,.catch() 可以集中处理错误。
  • 提供了 Promise.all() 等辅助函数,可以方便处理并发任务。

缺点

  • 链式调用过多时,代码仍可能变得冗长,尤其是在复杂场景下。
  • 对比 async/await,Promise 仍需要较多的手动处理和拆解。

3. Async/Await

概述

Async/Await 是基于 Promise 的语法糖,提供了更加同步的写法来处理异步操作。async 关键字将函数声明为异步函数,而 await 用于等待一个 Promise 完成,显著提高了代码的可读性。

示例

async function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Data fetched");
        }, 1000);
    });
}

async function processData() {
    try {
        const result = await fetchData();
        console.log(result);  // "Data fetched"
    } catch (err) {
        console.error(err);
    }
}

processData();

优点

  • 语法简洁:异步代码看起来像同步代码,易读易写。
  • 错误处理简单:可以使用 try...catch 进行错误捕获,和同步代码的错误处理保持一致。
  • 更容易处理复杂的异步逻辑:通过 await,可以线性地编写代码,而不必嵌套回调或 .then()

缺点

  • 需要浏览器支持或 Babel 等编译工具进行转译。
  • 不能轻易取消已启动的异步任务(例如 HTTP 请求)。
  • 虽然处理流程简单,但对于更复杂的异步流操作,表现仍不如 RxJS 中的 Observable。

4. Observable(RxJS)

概述

Observable 是 RxJS(Reactive Extensions for JavaScript)库中的核心概念,是一种更高级的异步处理方式。与 Promise 只能处理一次性结果不同,Observable 可以处理多个值,并且可以流式地响应异步事件。Observable 更像是一种可以多次发出值的流,可以用来处理时间流(Event Streams)、多次异步请求等。

示例

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
    setTimeout(() => {
        subscriber.next('Data 1');
        subscriber.next('Data 2');
        subscriber.complete();
    }, 1000);
});

observable.subscribe({
    next(value) { console.log(value); },  // "Data 1", "Data 2"
    complete() { console.log('Complete'); }
});

优点

  • 多值处理:可以像数据流一样处理多次值的发射,而不仅仅是一个值。
  • 取消异步操作:可以通过 .unsubscribe() 来取消正在进行的异步任务,Promise 没有这种能力。
  • 响应式编程:Observable 支持对事件流的操作符(例如 mapfiltermerge 等),可以轻松实现复杂的事件组合和处理。
  • 支持多种异步操作的高级控制,如并发、节流、去抖等,尤其适合事件流、大数据流处理等场景。

缺点

  • 学习曲线较陡,需要了解响应式编程(Reactive Programming)的基本概念。
  • 如果不使用 RxJS,浏览器原生不支持 Observable,需要额外引入库。

5. 关键点对比

特性CallbackPromiseAsync/AwaitObservable
语法复杂度简单中等简单中等
可读性差(回调地狱)最佳中等
错误处理复杂易于链式处理简单(try/catch)强大(catch,retry)
一次性结果处理否(可处理多个值)
取消异步任务
高级异步控制中等中等强大
并发处理通过手动实现Promise.all()通过多次 await 实现内建多种并发控制
过程管理容易
框架集成简单简单简单中等

6. 使用场景总结

  • Callback:适合简单的异步任务,但当异步操作复杂时,推荐使用 Promise 或 Async/Await 来避免回调地狱。
  • Promise:适合处理单个异步操作,特别是当需要链式处理多个异步任务时。
  • Async/Await:适合大多数场景,特别是需要同步风格代码的异步任务,代码简洁且易于维护。
  • Observable:适合需要处理多值异步流、响应事件、复杂异步任务的场景,尤其是需要高级控制(如取消、并发、错误重试)时。

结论

在 JavaScript 中,处理异步操作的方式随着技术的发展逐步演进。Callback 作为最基本的异步处理方法,在简单场景下仍然可用,但容易导致回调地狱。Promise 和 Async/Await 提供了更清晰的语法来处理异步任务,尤其是 Async/Await,可以写出几乎像同步代码一样简洁的异步代码。而 Observable 则为复杂的异步流控制提供了强大的工具,尤其适合那些需要高灵活性和事件流处理的应用场景。

理解并掌握这些异步处理方式,可以帮助我们在不同场景下选择最合适的工具,提高代码的可读性、可维护性和扩展性。

涉及到复杂的异步控制场景 - 例如持续执行的任务 ,非一次性必须完成的任务,推荐无脑rxjs

标签:Observable,异步,处理,Await,JS,Promise,Async,Data
From: https://blog.csdn.net/m0_38015699/article/details/142909358

相关文章

  • 毕业设计-基于Java+SSM+JSP的校园心理健康网站系统的设计与实现(源码+文档+部署视频)
    文章目录1.前言2.详细视频演示3.论文参考4.项目运行截图5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue6.选题推荐优秀毕设案例展示8.系统测试8.1系统测试的目的8.2系统功能测试9.代码参考10.为什么选择我?11.获取源码1.前言......
  • 两段相同的代码【async await】
    asyncfunctiondoSubmitFile(){constfileInput=document.getElementById('fileInput')constfileObj=fileInput.files[0]constformData=newFormData()formData.append('file',fileObj)try{constresponse=await_axi......
  • CSV、XML、JSON三种形式进行存储并读取
    下面是一个完整的Python示例代码,它可以生成简单的算式(加法、减法、乘法、除法),并将生成的算式和习题长期保存到CSV、XML和JSON三种格式中。代码包括生成算式的功能,以及将数据保存和读取的功能。1.代码实现pythonimportcsvimportjsonimportxml.etree.ElementTreeas......
  • Three.js的魅力 带你 进入 web 3D 世界的大门
    原生Three.js和Cesium.js案例。智慧城市数字孪生常用功能列表模型加载-使用three.js加载不同格式的模型。轮廓光辉光后期处理得各种效果。天空盒加载环境贴图效果相机视角动画物体沿着路径运动动画粒子效果围墙着色器效果类似echarts的three.js3d......
  • golang从http请求中读取xml格式的body,并转成json
    推荐学习文档golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔记专栏文章目录以下是在Go语言中从HTT......
  • mysql+navicat+eclipse+jsp
    mysqlserver5.5安装微信公众号搜软件智库,然后找到mysql5.5百度网盘下载对应自己电脑版本的mysql百度网盘:http://pan.baidu.com/s/1jI5oB6A提取密码:7act解压解压密码:rjzkgzh(软件智库公众号)readygo解压后,双击开始安装点击next 点击我接受,然后next......
  • vue中上传xlsx表格文件,并获取文件json数据【前端文件上传】
    import*asXLSXfrom"xlsx";onMounted(function(){document.getElementById('fileInput').addEventListener('change',function(){constfileObj=this.files[0]//console.log(fileObj)//......
  • Nuxt.js 应用中的 ready 事件钩子详解
    title:Nuxt.js应用中的ready事件钩子详解date:2024/10/12updated:2024/10/12author:cmdragonexcerpt:ready钩子是Nuxt.js中一个重要的生命周期事件,它在Nuxt实例初始化完成后被调用。当Nuxt已经准备好并准备开始处理请求或渲染页面时,这一钩子会被触发......
  • Nuxt.js 应用中的 kit:compatibility 事件钩子详解
    title:Nuxt.js应用中的kit:compatibility事件钩子详解date:2024/10/11updated:2024/10/11author:cmdragonexcerpt:kit:compatibility是处理浏览器兼容性问题的有效工具。正如本篇文章中所述,合理地利用这一钩子可以提升用户体验,并确保应用在不同环境中都能稳......
  • Nuxt.js 应用中的 close 事件钩子详解
    title:Nuxt.js应用中的close事件钩子详解date:2024/10/13updated:2024/10/13author:cmdragonexcerpt:close钩子是Nuxt.js中一个重要的生命周期事件,它在Nuxt实例正常关闭时被调用。当Nuxt应用的生命周期即将结束时,这一钩子会被触发,让开发者能够执行一些必要......