深入理解JS中的异步函数

首先明确一点,==异步函数不等于微任务==。
异步任务是JavaScript中一种在执行过程中不阻塞主线程的函数,一般用于处理耗时操作,比如网络请求,最后返回的是一个promise对象;
而微任务则是JavaScript事件循环的一种任务类型,主要用于处理 Promise 的回调和 MutationObserver 的回调;并且拥有比宏任务更高的优先级,事件循环会首先处理所有微任务,然后再处理宏任务
- 二者联系:异步函数会返回一个promise,而promise中的回调则是我们的微任务;而对于async和await,await关键字会暂停函数的执行,直到promise被解析或拒绝,这个过程中await后面的代码会被放入微任务队列中。
那异步函数到底是怎么执行的呢
1 | // 定义一个函数来获取用户数据 |
在 JavaScript 中,执行栈Call Stack和 任务队列Task Queue是理解异步操作执行机制的关键。我们可以通过分析上面提供的代码来了解它是如何执行的。
执行流程解析
主线程开始执行:
- 当代码开始执行时,JavaScript 引擎会将全局上下文推入执行栈。
**调用
fetchUserData(1)
**:- 主线程遇到
fetchUserData(1)
的调用,进入这个函数。 - 在
fetchUserData
函数内部,调用fetch
方法发起网络请求。 fetch
是异步操作,返回一个 Promise。此时,fetch
的执行会被放入 Web API 环境中处理,主线程不会等待它完成,而是继续执行后面的代码。
- 主线程遇到
返回到主线程:
fetchUserData
函数返回 Promise 对象后,控制权回到主线程,执行栈中的fetchUserData
函数被弹出。- 接下来,主线程继续执行后面的代码,输出
Fetching user data...
到控制台。
处理 Promise:
- 当
fetch
请求完成时,它会调用相应的回调函数(即then()
中的函数),这时会将这个回调函数放入微任务队列(Microtask Queue)。 - 微任务队列优先于宏任务队列(Task Queue),所以在主线程空闲时,会优先执行微任务队列中的任务。
- 当
处理响应:
- 当主线程完成当前执行栈中的所有任务后,开始检查微任务队列。
- 从微任务队列中取出
then()
中的回调函数,执行它。 - 在这个回调中,首先检查响应是否成功,如果成功,则调用
response.json()
,并返回解析后的 JSON 数据。 - 然后,继续执行下一个
then()
中的回调,输出用户数据到控制台。
处理错误:
- 如果在任何步骤中发生错误(例如网络请求失败),则会调用
catch()
中的错误处理函数,输出错误信息到控制台。
- 如果在任何步骤中发生错误(例如网络请求失败),则会调用
执行栈与任务队列的关系
执行栈:
- 主要用于同步代码的执行。当函数被调用时,它会被推入执行栈,执行完成后从栈中弹出。
微任务队列:
- 存放
Promise
的回调和其他微任务。当主线程空闲时,会优先执行微任务队列中的任务。
- 存放
总结
在这段代码的执行过程中,JavaScript 的事件循环机制确保了主线程不会被阻塞。尽管 fetch
是异步操作,但主线程在发起请求后继续执行后面的代码,保持响应能力。最终,网络请求完成后,相关的回调被放入微任务队列,并在主线程空闲时执行,从而处理异步操作的结果。这样,整个过程保证了代码的高效和非阻塞特性。
fetch原理
好的,让我们深入探讨一下“fetch 的执行会被放入 Web API 环境中处理”这句话的含义。
Web API 环境
在 JavaScript 中,尤其是在浏览器中,存在一个称为 Web API 的环境。这些 API 提供了与浏览器和操作系统的交互能力,例如处理 DOM、发起网络请求、定时器等。Web API 是在 JavaScript 引擎之外的环境中运行的。
fetch
的工作机制
异步调用:
- 当你调用
fetch(url)
时,JavaScript 引擎并不会立即执行这个请求,而是将这个请求的处理交给 Web API。此时,fetch
函数立即返回一个 Promise 对象,表示请求的未来结果。
- 当你调用
请求的处理:
- Web API 接收到
fetch
请求后,会去执行实际的网络操作(例如,通过 HTTP 协议向服务器发送请求)。这个过程是异步的,意味着 JavaScript 引擎不会等待这个请求完成,而是继续执行后面的代码。
- Web API 接收到
Promise 的状态变化:
- 一旦网络请求完成(无论是成功还是失败),Web API 会将结果(例如,响应数据或错误信息)传递回 JavaScript 引擎。此时,Promise 的状态会被更新:
- 如果请求成功,Promise 的状态变为“已解决”(fulfilled),并将响应对象作为值。
- 如果请求失败,Promise 的状态变为“已拒绝”(rejected),并将错误信息作为值。
- 一旦网络请求完成(无论是成功还是失败),Web API 会将结果(例如,响应数据或错误信息)传递回 JavaScript 引擎。此时,Promise 的状态会被更新:
微任务队列:
- 当 Promise 的状态变化时,Web API 会将与之相关的回调(即
then()
或catch()
中的函数)放入微任务队列。这样,JavaScript 引擎可以在主线程空闲时执行这些微任务。
- 当 Promise 的状态变化时,Web API 会将与之相关的回调(即
事件循环的角色
事件循环(Event Loop)是 JavaScript 的核心机制之一,它负责协调主线程和异步操作之间的执行。当主线程完成当前执行栈中的所有同步操作后,事件循环会检查微任务队列,优先执行其中的任务(如 then()
和 catch()
中的回调)。因此,尽管 fetch
是异步的,最终结果会在主线程空闲时得到处理。
总结
综上所述,“fetch 的执行会被放入 Web API 环境中处理”意味着当你调用 fetch
时,实际的网络请求是由浏览器的 Web API 处理的,而不是在 JavaScript 引擎的执行栈中同步执行的。这种设计使得 JavaScript 能够高效地处理异步操作,保持主线程的响应能力,从而实现非阻塞的编程模型。
- Title: 深入理解JS中的异步函数
- Author: tianyi
- Created at : 2025-04-26 10:46:35
- Updated at : 2025-04-26 10:59:10
- Link: https://github.com/ztygod/2025/04/26/深入理解JS中的异步函数/
- License: This work is licensed under CC BY-NC-SA 4.0.