summary
type
category
tags
slug
status
date
finished_date
icon
password

什么是异步编程

假设你正在准备晚餐,如果以一种同步的方式工作:你必须等鸡肉烤好后才能去煮意大利面。
但为了提高效率,可以通过使用异步操作:将鸡肉放进烤箱开始烤后设置一个计时器,并在在等待鸡肉的过程中,开始准备意大利面。

为什么 JS 需要异步编程

  • JS 最初被设计为在浏览器中运行,它是单线程的,这意味着它一次只能执行一个任务。在执行长时间操作(如网络请求、文件读写等)时,整个程序将会停滞,直到操作完成。
  • 为了避免阻塞这个线程,JS 使用了事件循环,允许非阻塞的操作,即异步编程的核心。

什么是事件循环

Event Loop
一种用来管理多个事件和异步操作的机制
同步和异步任务会进入不同的执行环境
  • 同步的进入主线程,即主执行栈
  • 异步的进入任务队列
📢
任务队列中的任务又分为两种

宏任务

Macro-tasks
  • 定时器事件:setTimeoutsetIntervalsetImmediate
  • 渲染事件:解析 DOM、计算布局、绘制
  • 交互事件:如鼠标点击、键盘事件
  • I/O 操作:网络请求、文件读写

微任务

Micro-tasks优先级高于宏任务
  • Promise .then().catch().finally() 回调📦详见下文)
  • async/await 语法中的 await 关键字后面的代码
  • MutationObserver 监听 DOM 变化时的回调函数
  • Node.js 的 process.nextTick
📢
事件循环的每个循环迭代称为一个 tick。在每个 tick 中,以下步骤会被执行:
  1. 执行一个宏任务(从宏任务队列中取出下一个任务执行)
  1. 执行所有排队的微任务(在这个 tick 中,每当有微任务被添加,它们就会被立即执行,直到微任务队列为空)
notion image
这段代码的执行顺序序号是 1>3>2。
即使延迟时间为 0,回调也只能在所有同步代码执行完毕后。

什么是回调函数

在 JS 中,函数是一等公民,意味着可以像其他数据类型一样处理函数:可以将函数作为参数传递给其他函数,也可以作为值从函数返回。回调函数是作为参数传递给另一个函数的函数
When you pass a function as an argument, remember not to use parenthesis.
  • Right: calculator(5, 10, calc);
  • Wrong: calculator(5, 10, calc());
💣
Promise 出现前,JS 的异步编程依靠回调。回调函数容易导致代码结构混乱,产生“回调地狱” (Callback Hell)。
notion image

什么是 Promise

可以将 Promise 想象成一个未来某个时刻可能得到的结果的承诺,它有三种状态
  • Pending(待解决):初始状态。
  • Fulfilled(已兑现):操作成功。
  • Rejected(已拒绝):操作失败。
通过调用 resolve 和 rejected 改变当前 Promise 状态
通过调用 resolve 和 rejected 改变当前 Promise 状态

基本构造

链式调用

适合处理简单的异步操作,或者当需要更精细的控制 Promise 链。
  • then 方法最多可以接受两个参数(第二个参数只捕获到它之前的 Promise 错误)
    • catch 能够捕获之前所有 Promise 链中的错误
    🖌️
    链式调用怎么实现的?
    1. 每个 .then() 方法都返回一个新的 Promise 对象,这个新的 Promise 对象可以用来连接下一个 .then() 调用,这样就形成了链式调用。
    1. Promise 内部使用了微任务来异步执行 .then() 方法的回调函数。这意味着每个 .then() 中的回调函数会等待当前 JS 执行栈清空后执行,这样可以确保异步操作按照正确的顺序执行。

    Async 与 Await

    ES2017 中引入,建立在 Promise 之上的语法糖,允许以同步的方式编写异步代码。提供了更简洁和直观的方式来处理复杂的异步操作,特别是涉及多个步骤或条件语句。
    • async 函数:函数会隐式地返回一个 Promise。
    • await 关键字:在异步函数内使用,它会暂停函数的执行,等待 Promise 的解决。
    notion image

    Generator

    async/await 内部使用生成器函数来实现异步流程的控制 → Generator 允许函数的执行在某一点挂起(通过 yield 关键字),然后在稍后的某个时候恢复执行

    处理并发

    Concurrency methods
    • Promise.all()
    当有多个异步操作需要执行,并希望等待它们全部完成时,它允许同时处理多个 Promise 对象,然后返回一个 Promise 对象。
    • Promise.allSettled():类似于 Promise.all,但它等待所有的 Promise 完成,无论是解决还是拒绝,并返回一个对象数组,每个对象表示对应的 Promise 的结果。
    • Promise.race():在一组 Promise 中的任何一个解决或拒绝时就解决或拒绝,返回一个 Promise。
    • Promise.any():返回一组 Promise 中第一个解决的结果。如果所有 Promise 都拒绝,它也拒绝。
    • Promise.resolve() Promise.reject():用于快速创建一个状态为解决或拒绝的 Promise。

    一些缺点

    • 不可取消:如果有一个长时间运行的异步操作,无法中途停止。
    • 错误处理:如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
    • 单次解决: Promise 只能解决或拒绝一次,它们无法处理重复发生的事件。
     
    Rylan
    Rylan
    Just be a rock