给你一分钟的时间 请你说出最终的打印顺序(结果在最下面):
console.log('start');
setTimeout(() => {
console.log('setTimeout');
Promise.resolve().then(() => {
console.log('promise2');
});
}, 0);
new Promise((resolve) => {
resolve();
console.log('promise1');
}).then(() => {
console.log('then');
});
console.log('end');
如果你一分钟没有思考出来答案,说明你还对事件循环的过程不熟悉
什么是js的事件循环?
当接触到一个新概念时,第一反应是基于你已有的知识去问 “为什么会有这个东西”
就比如:“js为什么会有事件循环”
先看js,js作为一个单线程语言,他的主要功能是解释性,为用户提供操作入口,是一个人机交互的语言
而浏览器是多线程的,你可以理解一个浏览器能打开多个标签页,每一个标签页都是一个进程的
js为了适配在浏览器操作,和用户进行交互,必定要做一个事件处理机制去解决这个适配的问题
因为js是单线程,当多个任务需要进行处理时,必定需要排队,因此有了任务队列 一件事情做完才能干另外一件事情
例如遇到了一个这样的场景时,当客户端发送一个请求到服务器上时,服务端返回数据通过网络延迟返回消息,这个时候cpu的计算使用是不太密集的,
JS一般将任务耗时比较重的的任务分为两种类型
计算密集型任务:当JavaScript执行一些计算任务时(如数学运算、数组排序等),这些任务通常是CPU密集型的,CPU会忙于计算。此时,CPU在等待计算完成后,才能继续执行下一个任务。如果计算任务很耗时,就会导致任务积压,其他任务不得不等待。
IO密集型任务:JavaScript中很多任务是IO密集型的,例如从网络获取数据(比如通过AJAX请求)。这类任务通常会涉及到网络延迟或者硬盘读写等操作,速度较慢。
如果是计算密集型任务,这种情况合理,也能接受
但如果是IO密集类任务,CPU资源根本就没有用到多少,还要去等待IO返还的延迟,这样就会造成CPU资源的浪费,也会导致用户一致在等待这个进程,体验很差
JS的设计者想到了这个问题后,如果遇到IO密集类的任务情况下,先将任务暂时挂起,等待IO设备返还完数据后再回来执行这个过程。
就这样,这么一个处理任务机制的过程,就在js中命名为“事件循环”
事件循环依赖于任务队列,而任务队列的正确执行需要事件循环这个过程
任务队列
任务队列一般有两种任务类型
1.同步类任务
2.异步类任务
执行过程很简单,先执行同步任务,如果在程序执行的同步任务碰见异步任务,将异步任务放到任务队列里面 等同步任务执行完,任务队列就会告知异步任务开始执行
而异步任务又分为两种
- 宏任务
- 微任务
关于宏任务的解释:宿主环境提供的任务,一般为浏览器或者Node.js 细化到代码层面上,这些方法是宏任务
- setTimeout/setInterval
- I/O 操作
- UI 渲染
- setImmediate (Node.js)
- requestAnimationFrame (浏览器)
- script 整体代码
关于微任务的解释:
一般由javascript引擎提供的任务 细化到代码层面上,这些方法是微任务
- Promise.then/catch/finally
- process.nextTick (Node.js)
- MutationObserver (浏览器)
- queueMicrotask()
执行过程是 当前同步任务(宏任务)执行完成后->微任务队列查找还有没执行完的微任务->微任务执行完后(清空微任务队列),这就可以称作一次事件循环,JS就是一直在反复这个过程,就称为事件循环
答案是:start promise1 end then setTimeout promise2