一、JS任务和事件循环
Js是一门单线程语言,每一个时刻只能执行一个任务(JS引擎在执行任务时,是一个一个执行的,如果有多个任务,则后面的任务只能等待)
1.1JS任务
如果js的任务都是同步任务的话,那么遇到定时器、网络请求等这类型需要延时执行的任务,页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的任务,用户体验就很烂,所以我们需要引入异步任务,让这些执行会很长时间的代码都往后稍稍
同步任务:同步任务不需要进行等待可立即看到执行结果,比如console
异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求
1.2事件循环
当消息队列(存放任务的队列)为空时,就会等待直到消息队列变成非空。而且主线程只有在将当前的消息执行完成后,才会去取下一个消息。这种机制就叫做事件循环机制,取一个消息并执行的过程叫做一次事件循环。
- 当有任务时:
- 从最先进入的任务开始执行(第1步)
- 没有其他任务时:
- 休眠直到出现任务,然后重新转到第 1 步
二、JS执行机制 同步任务和异步任务
2.1JS执行机制原理
- js代码开始执行后,主线程执行栈中会把任务分为两类(
同步任务和异步任务) - 主线程执行栈
优先执行同步任务,异步任务会被放入特定的处理程序中,满足条件后,被放到消息(任务/事件)队列中,主线程执行栈中所有的同步任务执行完毕之后,通过事件循环去消息(任务/事件)队列中,将优先满足条件的程序放入主线程执行栈中执行。事件循环,周而复始。

setTimeout(() => {
console.log('定时器开始啦!定时0秒钟,大家是不是觉得我会立马执行!');
}, 0);
console.log('你们猜错啦!同步任务优先执行!');
setTimeout(() => {
console.log('呜呜呜,我比上一个定时器多延时了一点,在所有同步任务都执行完后,没有优先满足条件,我要最后执行了');
}, 0.1);- 代码
从上往下执行,先碰到了定时器,主线程执行栈认定它为异步任务,于是把它丢给了Event Table(异步任务特定的处理程序)并且开始计时0秒钟,当0秒钟到了以后就注册定时器的回调函数,并且把函数里的内容放入消息队列当中 所有的同步代码都执行完后,才会执行消息队列中的内容,异步任务谁先满足条件,谁就优先放入消息队列中,并且优先执行
所以这里的执行顺序是
- 1.碰到定时器 丢到Event Table,开始计时,满足条件之后再交给消息队列
- 2.碰到同步任务console,直接出结果 控制台打印
- 3.碰到定时器 丢到Event Table,开始计时,满足条件之后再交给消息队列
- 4.所有同步任务执行完毕,去消息队列中找有没有满足条件的程序,放入主线程执行栈中执行
- 5.第一个定时器先满足条件优先执行,第二个随后执行
- 6.检测到任务队列都已执行完成,代码执行结束
三、异步任务中的宏任务和微任务
3.1微任务和宏任务概念讲解
异步任务细分为宏任务和微任务,微任务的执行顺序在宏任务之前,即使是宏任务优先满足条件,但是微任务可以插队
在ES3 以及以前的版本中,JavaScript本身没有发起异步请求的能力,也就没有微任务的存在,(以前都是由宿主(node、浏览器)发起的)在ES5之后,JavaScript引入了Promise,不需要浏览器,JavaScript引擎自身也能够发起异步任务了。
Tick(在事件循环中,每进行一次循环操作称为 Tick)会触发浏览器渲染,Promise不会触发,所以Promis更加轻量级
宏任务牵扯的资源更多,会引发浏览器重绘,而微任务更加轻量级,微任务的执行顺序在同步任务后,宏任务之前


常用的微任务 —— Promise
4.2 async await执行顺序(题目以及讲解)
Promise是处理异步操作的一种方法(典型案例就是回调地狱),而大家常用的async/await 是基于 Promise 的一种语法糖,它提供了一种更直观和同步化的方式来编写异步代码。
async function a (){} async顾明思议就是异步的意思,但是函数被调用时,代码会正常立即执行(就是正常的同步任务),但是当碰到await关键词时,await后面跟着的代码会立即执行,但是await下一行的语句会作为微任务加入到微任务队列中,上代码!
async 函数只有从 await 往下才是异步的开始,并且await后面的代码立即执行,await 之后的代码 相当于.then里面的代码 => 微任务
async function getPromise() {
return '我是getPromise函数';
}
console.log(1);
async function fn() {
console.log(2);
let str = await getPromise();
console.log(str);
console.log(4);
}
fn();
setTimeout(() => {
console.log('我是一个大大的宏任务,我执行的不如微任务快');
}, 0);
console.log(3);
答案:
1
2
3
我是getPromise函数
4
我是一个大大的宏任务,我执行的不如微任务快- 1.同步代码console.log(1)执行
- 2.async修饰的函数正常执行,console.log(2)
- 3.遇到了await,await后面的代码立即执行,剩下的被当做微任务丢给了异步处理程序,所以打印str和4的代码被丢进了微任务队列里
- 4.定时器定时0秒,丢进宏任务里
- 5.打印3
- 6.同步任务解决完毕,开始去消息队列里找满足条件的任务,优先完成微任务, 发现有微任务,打印’我是getPromise函数’,打印4
- 7.微任务执行完,轮到宏任务,打印’我是一个大大的宏任务,我执行的不如微任务快’
















