【js】setTimeout、Promise、Async/Await 的区别
三者在事件循环中的是不同的,事件循环中分为宏任务队列和微任务队列
- 其中setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行;
- promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行;
- async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
setTimeout
console.log('script start') //1. 打印 script start setTimeout(function() { console.log('settimeout') // 4. 打印 settimeout }) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数 console.log('script end') //3. 打印 script start // 输出顺序: // ->script start // ->script end // ->settimeout
Promise
Promise本身是同步的立即执行函数,
当在executor中执行resolve或者reject的时候,
此时是异步操作,
会先执行then/catch等,
当主栈完成后,才会去调用resolve/reject中存放的方法执行,
打印p的时候,是打印的返回结果,一个Promise实例。
console.log('script start') let promise1 = new Promise(function(resolve) { console.log('promise1') resolve() console.log('promise1 end') }).then(function() { console.log('promise2') }) setTimeout(function() { console.log('settimeout') }) console.log('script end') // 输出顺序: // ->script start // ->promise1 // ->promise1 end // ->script end // ->promise2 // ->settimeout
当JS主线程执行到Promise对象时,
- promise1. then() 的回调就是一个 task
- promise1 是 resolved或rejected: 那这个 task 就会放入当前事件循环回合的 microtask queue
- promise1 是 pending: 这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
- setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况
async/await
async 函数返回一个 Promise 对象,当函数执行的时候,
一旦遇到 await 就会先返回,
等到触发的异步操作完成,再执行函数体内后面的语句。
可以理解为,是让出了线程,跳出了 async 函数体。
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end') } async function async2() { console.log('async2') } console.log('script start'); async1(); console.log('script end') // 输出顺序: // ->script start // ->async1 start // ->async2 // ->script end // ->async1 end
拓展:
// 面试题 Promise.resolve().then(()=>{ console.log('Promise1'); setTimeout(()=>{ console.log('setTimeout2') },0) }) setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') }) }) // Promise1 setTimeout1 Promise2 setTimeout2
let p = Promise.resolve().then(() => { console.log(p); const timer2 = setTimeout(() => { console.log('timer2') }, 0) }); const timer1 = setTimeout(() => { console.log('timer1') Promise.resolve().then(() => { console.log('promise2') }) }, 0) console.log('start');
代码运行步骤:
1、遇到Promise.resolve().then作为微任务,加入到微任务队列
2、timer1是宏任务,加入到宏任务队列
3、console.log同步代码,输出`start`,主线程中同步任务执行完。
4、微任务队列中有Promise.resolve().then,输出p,因为此时p没有resolve(),以及reject()终止掉,因此会输出`pending`。
4、timer2是宏任务,加入到宏任务队列,此时宏任务队列中有timer1、timer2。
5、微任务执行结束,进入到下一轮宏任务阶段。运行timer1,输出`timer1`,Promise.resolve().then是微任务。
6、宏任务结束,运行微任务,输出`promise2`。
7、微任务运行结束。此时宏任务队列中还有timer2,因此输出`timer2`
相关资料:
欢迎关注我,一起进步!扫描下方二维码即可加我QQ

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通