js宏任务和微任务
事件循环就是Event Loop,是javascript一个特殊的地方.特殊就在于javascript是单线程语言,注定了异步操作有别于多线程语言.执行栈和任务队列是javascript执行异步任务的管理方式,
宏任务和微任务是js异步任务更细粒度的划分
单线程
进程和线程是操作系统中的概念,线程是进程的最小单位,一个进程可以包含多个线程,此处不再赘述。
javascript在设计之初就是单线程,程序运行时,只有一个线程存在,在特定的时候只能有特定的代码被执行.这和javascript用途有关;
它是一门浏览器脚本语言,通常是用来操作DOM的,如果是多线程,一个线程进行了删除DOM操作,另一个添加DOM,此时该如何处理;
所以javasecript在设计之初就是便是单线程的
虽然HTML5增加了 web Work 可用来另开一个线程,但是该线程仍受主线程的控制,没有Window对象,不能操作DOM;
所以javascript本质依然是单线程.所有同步、异步任务都是在主线程中执行
单线程的javascript一段一段的执行,前面的执行完了,再执行后面的;
试想一下,如果前一个任务需要执行很久,比如说接口请求、I/O操作,那后面的任务只能干等吗? : 干等不仅浪费了资源,而且页面交互程度也很差.
javascript意识到了这个问题,他们将任务分成了 同步任务和异步任务,对于二者有不同的处理
明确什么是同步任务、异步任务
1 let name = '小明' //同步任务1 2 window.addEventListener('popstate', (e) => { //同步任务2 3 console.log (e) //异步任务 4 })
这里是两条语句,一是生命name并赋值,而是添加 window 的 popstate事件监听.
对应的这里产生了两个任务,是同步任务 , 主线程按照代码书写顺序先执行任务1(name声明和赋值),
在执行同步任务2: (添加window的popstate事件的监听).
监听器回调里要去执行console.log(e),所以这条语句也产生了一个任务,而它是一个异步任务,确切的说是整个回调函数产生了一个异步任务
//js代码: 同步代码 异步代码
//只写同步代码,js的执行顺序会非常清晰,自上而下执行
//异步代码: setTimeout setInterval Promise process.nextTick
// 宏任务 和 微任务 关系到js代码的执行顺序
宏任务: script(全局作用域中的同步代码) setTimeout , setInterval
微任务: Promise, process.nextTick(node.js环境)
//宏任务队列
//微任务队列
1 //全局作用域: 立即添加到宏任务执行 2 console.log(123) 3 //使用setTimeout延迟执行函数,js执行到setTimeout时候,里面函数先注册,2秒后添加到宏任务中去 4 setTimeout(function(){ 5 console.log('456') 6 },2000); 7 // js执行顺序,由外面的区域到里面的区域,宏任务和微任务交替执行
执行栈、任务队列
/**
详细分析 异步宏任务 异步微任务执行顺序
1.明确什么是同步任务, 什么是异步任务
2.执行栈, 任务队列
首先,执行栈管理同步任务,任务队列管理异步任务.同步任务没啥、异步任务分为 异步宏任务, 异步微任务
常见宏任务 和微任务: 文章上文
*/
1 console.log(1) //同步任务A 2 3 4 setTimeout( //同步任务B 5 () => {console.log(2)} //任务B产生的异步宏任务 6 , 300) 7 8 new Promise( //同步任务C 9 (resolve) => { 10 console.log(3); 11 resolve(4); 12 }).then( //任务C执行过程中resolve(4)语句产生的异步微任务 13 (num) => {console.log(num)}) 14 15 setTimeout( //同步任务D 16 ()=> { console.log(5) } //任务D产生的异步宏任务 17 , 800)
/**
1.javascript执行时,同步任务会排好队,在主线程上执行A, 完了B, B完了C ......知道执行栈里无其他任务,
排队的地方叫执行栈,执行A没啥问题,执行到B时,B是一个setTimeout任务,我们知道它会产生一个异步任务,但不是马上产生,而是等待300MS产生一个异步宏任务
这个异步任务的目的时去打印数字2,这是主线程没有傻傻等待300MS再去打印2,而是将任务挂起,继续往下走去执行同步任务C
2.主线程继续往下执行同步任务C,这时候同步任务C有俩部分,一是console.log(3),一是resolve(4),所以先后执行console.log(3),resolve(4),
我们知道resolve(4)执行会返回promise对象, 而promise对象里有自己的执行代码,(这段代码就是console.log(num)),
那么主线程是继续往下执行下一个同步任务? 还是转到执行resolve(4)返回的promise对象中的代码呢?
答案就是会执行下一个同步任务! 这个时候resolve(4)所返回的promise对象就产生了一个异步微任务,主线程将它挂起,挂起的方法就是将它塞到异步微任务执行队列当中,先不管他
3.下一个任务还是setTimeout,和上一个一样,只不过这个要等800ms才会产生一个异步宏任务,
回头看看之前产生的那个异步宏任务去哪了? 别急,300ms还没到呢,
主线程一路从 A 往下 D 这个期间异步任务BB 还没创建好呢,创建好后主线程会把它挂起来.
1 console.log(1); //任务A 2 setTimeout(function(){ //任务B 3 console.log(2) //任务B产生的异步宏任务b 4 }, 200); 5 new Promise( //任务C 6 (resolve) => { 7 console.log(3) 8 resolve(4) 9 } 10 ) 11 .then( //任务C执行过程中resolve(4)语句产生的异步微任务c 12 (num) => { console.log(num) } 13 ) 14 console.log(5); //任务D
*/

浙公网安备 33010602011771号