惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
MyScale Blog
MyScale Blog
博客园 - 聂微东
有赞技术团队
有赞技术团队
The Cloudflare Blog
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
T
The Blog of Author Tim Ferriss
D
Docker
L
LangChain Blog
Vercel News
Vercel News
C
Check Point Blog
博客园 - Franky
博客园 - 三生石上(FineUI控件)
Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
人人都是产品经理
人人都是产品经理

博客园 - smile轉角

【js】ES5,ES6继承是如何实现的 【面试题】思维逻辑方面 【js】js内置对象Error(错误机制) 【TS】学习笔记 【js】CommonJS、AMD、CMD三种规范 【其他】查看Animate.css官网动画没有效果 【vue3】父子组件通信之 vue3 defineProps,defineEmits ,defineExpose 【js】JS严格模式有什么特点 【css】使用弹性盒子布局时,省略号问题 【vue】 Failed to load resource: the server responded with a status of 404 (Not Found) 【第三方】富文本调研 【js】元素是否在可视区范围内 【js】json的相关操作 【vue3】资料 【css】展示背景图片的底部部分 【html】 svg 【html5】html5中input 标签 type值为range时,修改其默认css 【js】forEach,for...in,for...of 区别 【js】map,reduce,filter的区别
【js】setTimeout、Promise、Async/Await 的区别
smile轉角 · 2023-04-14 · via 博客园 - smile轉角

三者在事件循环中的是不同的,事件循环中分为宏任务队列和微任务队列

  • 其中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`

 相关资料: