前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Promise executor 同步执行
JavaScript异步与 Promise

new Promise 里传的函数是同步执行还是异步执行?

executor 是同步执行的。new Promise(fn) 这一行执行时,fn 会被立即调用一次,里面的 console.log 会马上打印。异步的只有 then、catch、finally 注册的回调,它们要等当前同步代码跑完,才从微任务队列里被取出来执行。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#异步与 Promise#异步编程
先看核心答案读代码示例
理解线索

构造是同步的,通知是异步的

  1. executor传给 new Promise 的函数,构造时立即同步调用,只调用一次
  2. resolve 和 reject同步地把状态从 pending 改成 fulfilled 或 rejected,只有第一次调用有效
  3. then 回调状态确定后作为微任务排队,等同步代码全部结束才执行

executor 同步执行不代表它包的操作是同步的。里面的 setTimeout 或网络请求照样是异步完成,只是「发起」这个动作发生在 new 的当下。

核心回答

先记住这个答案

executor 是同步执行的。new Promise(fn) 执行到这一行时,fn 会被立即调用,里面的代码和外面的同步代码按书写顺序依次运行。在 executor 里调用 resolve(),也只是把 Promise 的状态同步改成 fulfilled,并不会马上执行 then 的回调。then 回调会被放进微任务队列,等当前这段同步代码全部跑完才执行。所以一句话记:构造同步,通知异步。

  • new Promise(fn) 时 fn 立即同步执行
  • resolve() 只改状态,不会马上执行 then 回调
  • then 回调一定异步,哪怕 Promise 早就成功了
  • executor 里同步抛错,Promise 直接变成 rejected

先看一道打印顺序题

面试里这个知识点几乎都以打印顺序题的形式出现。先自己猜一下输出,再看结果。

executor 和 then 谁先打印JavaScript
console.log('start')

const p = new Promise((resolve) => {
  console.log('executor') // new 的时候就执行
  resolve('done') // 状态马上变成 fulfilled
  console.log('after resolve') // resolve 不会中断 executor,这行照样打印
})

p.then((value) => console.log('then:', value)) // 回调进微任务队列

console.log('end')
查看输出与解释
start
executor
after resolve
end
then: done

前四行都是同步打印的,顺序和代码书写顺序一致。then 的回调虽然注册时 Promise 已经成功了,也不会立刻执行,而是排进微任务队列,等最后一行 console.log('end') 跑完才轮到它。 还有一个细节:resolve('done') 之后的 after resolve 依然打印了。resolve 只是改状态,不是 return,不会跳出 executor。如果想让后面的代码不执行,要写成 return resolve('done')。

为什么要这样设计

executor 同步执行,是为了让你能在构造的那一刻就把异步操作发起。比如把 setTimeout 包成 Promise,写在 executor 里的 setTimeout 调用会在 new 时立刻注册定时器,不会因为「还没人调用 then」而拖延。Promise 从创建起就已经在干活了,这也是它被叫做「急切求值」的原因:不管有没有人 then,里面的操作都会执行。

then 回调必须异步,则是为了顺序可预测。假设 Promise 已经成功时 then 回调同步执行、还没成功时异步执行,同一段代码的执行顺序就要看运气。规范规定回调一律异步,你写在 then 后面的同步代码永远先于回调执行,这样就不用去猜。

executor 里的异步代码和同步错误

executor 本身同步,但它包裹的操作可以是异步的,这两件事要分开看。

在 executor 里放 setTimeoutJavaScript
const p = new Promise((resolve) => {
  console.log('1 executor 开始')
  setTimeout(() => {
    console.log('3 定时器触发')
    resolve('ok') // 这时状态才变成 fulfilled
  }, 100)
  console.log('2 executor 结束,Promise 还是 pending')
})

p.then((v) => console.log('4 then:', v))
查看输出与解释
1 executor 开始
2 executor 结束,Promise 还是 pending
3 定时器触发
4 then: ok

executor 同步跑完时,定时器还没触发,Promise 处于 pending(等待中)。100 毫秒后回调执行 resolve('ok'),状态才确定,then 回调随后作为微任务执行。

executor 里同步抛错
executor 执行时如果同步 throw 了一个错误,Promise 构造器会把它捕获,Promise 直接变成 rejected,错误可以用 catch 接住,外面的代码不会被打断。但如果错误是在 executor 里的 setTimeout 回调中抛的,那时 executor 早就执行完了,构造器已经管不到,这个错误会变成一个普通的未捕获异常,Promise 一直停在 pending。
回答前,多想一步

容易答错的地方

以为 Promise 里的代码都是异步的
很多人看到 Promise 就默认「里面的都异步」,于是把 executor 的打印排在 end 后面。实际上 executor 和普通函数调用没区别,异步的只有 then、catch、finally 这些回调。
以为调用 resolve 就会立刻执行 then 回调
resolve 只负责改状态。回调执行的时机永远是「当前同步代码结束之后」,所以哪怕 Promise 一创建就成功了,then 回调也要排队。
以为 resolve 之后的代码不会执行
resolve 不是 return。它后面的语句会继续跑,只是再调用 resolve 或 reject 已经无效,因为状态只能改一次。
试着用自己的话回答

面试官还会怎么问?

如果 then 回调里再 new Promise,里面的 executor 什么时候执行?

在那个 then 回调执行的时候同步执行。executor 永远在 new 的那一刻运行,只不过这次 new 本身发生在一个微任务里。

连续调用两次 resolve 或者先 resolve 再 reject 会怎样?

只有第一次有效。Promise 状态从 pending 改成 fulfilled 或 rejected 之后就锁定了,后面的调用会被静默忽略,不报错也不生效。

async 函数里 await 之前的代码是同步的吗?

是的。调用 async 函数时,函数体会同步执行到第一个 await 为止,这和 executor 同步执行是一个道理。await 之后的代码才会变成微任务,在当前同步代码结束后继续。

从一道题,走向一组知识

把知识连起来

异步与浏览器

JavaScript 事件循环如何执行?

then 回调什么时候执行取决于微任务队列,事件循环讲的正是同步代码、微任务、宏任务的先后。

函数与作用域

arguments 和函数的形参是一回事吗?改了一个另一个会变吗?

executor 收到的 resolve 和 reject 就是两个普通的函数参数,名字可以随便起。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Promise() constructor

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 先看一道打印顺序题
  3. 为什么要这样设计
  4. executor 里的异步代码和同步错误
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑