You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript fetch()执行流程存疑:实验与理论不符问题排查

解析fetch() Promise执行顺序与预期不符的原因

核心本质:浏览器事件循环的多优先级任务队列机制

浏览器的事件循环并非只有单一的宏任务队列,而是存在多类型、不同优先级的任务队列。fetch的网络响应回调属于高优先级I/O任务队列,其执行时机既不是普通微任务,也不是和setTimeout同优先级的普通宏任务。

你的实验执行流程逐阶段拆解

我们一步步梳理代码的实际执行逻辑:

  1. 当前宏任务执行阶段

    • 输出start,将第一个setTimeout回调注册到定时器宏任务队列
    • 将第一个Promise.resolve().then回调注册到微任务队列
    • 输出calling fetch,浏览器立即发起网络请求(在事件循环外并行处理)
    • 输出done calling fetch,连续执行13次delay(此时网络请求已完成,但浏览器必须等待当前宏任务执行完毕才能触发后续逻辑)
    • 将第二个Promise.resolve().then回调注册到微任务队列
    • 将第二个setTimeout回调注册到定时器宏任务队列
    • 执行1次delay,输出end,当前宏任务执行完毕
  2. 微任务队列清空阶段

    • 按注册顺序执行微任务队列中的两个Promise回调:输出start promise handler→end promise handler→start 2nd promise handler→end 2nd promise handler,微任务队列彻底清空
  3. 高优先级I/O任务执行阶段

    • 浏览器优先处理已完成的网络请求对应的fetch任务:resolve fetch的Promise,将其then回调加入微任务队列
    • 立即清空新生成的微任务队列:执行fetch的成功回调,输出success start fetch handler→success end fetch handler
  4. 普通定时器宏任务执行阶段

    • 按注册顺序执行定时器宏任务队列中的两个setTimeout回调:输出start macrotask→end macrotask→start 2nd macrotask→end 2nd macrotask

你的两个预期不成立的具体原因

  1. 预期1错误:fetch回调不会插入当前微任务队列
    当网络请求完成时,当前宏任务仍在执行delay循环,浏览器无法中断正在执行的宏任务去修改微任务队列。只有等当前宏任务执行完毕、现有微任务队列清空后,浏览器才会处理fetch的resolve逻辑,此时才会将fetch的then回调加入微任务队列执行。

  2. 预期2错误:fetch任务优先级高于定时器任务
    浏览器对不同类型的宏任务队列设置了优先级:网络I/O完成后的回调任务优先级高于定时器任务。因此在微任务清空后,会先执行fetch的resolve任务,再执行setTimeout的回调。

内容的提问来源于stack exchange,提问作者actor_deny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:27:27