本文主要是介绍js异步之宏任务(marcroTask)和微任务(microTask),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
先看一到面试题
写出console.log的输出顺序
console.log(100);setTimeout(()=>{console.log(200);
})setTimeout(()=>{console.log(201);
})Promise.resolve().then(()=>{console.log(300);
})console.log(400);// 100 400 300 200 201
// 为什么300比200先打印
为什么300比200先打印这里就引出了宏任务和微任务????
什么是宏任务和微任务
宏任务包括:setTimeout setInterval Ajax DOM事件
微任务:Promise async/await
微任务比宏任务的执行时间要早
异步和单线程
异步和单线程是相辅相成的,js是一门单线程脚本语言,所以需要异步来辅助
异步和同步的区别:
- 异步不会阻塞程序的执行,
- 同步会阻塞程序的执行,
前端使用异步的场景:
- 定时任务:setTimeout,setInverval
- 网络请求:ajax请求,动态
<img>
加载 - 事件绑定
//ajax请求代码示例
console.log('start')
$.get('./data1.json',function(data1){console.log(data1)
})
console.log('end')
加载示例:
事件绑定示例:
也就是请求处理过程中,你不能闲着,会产生异步的请求,回头再处理,然后继续执行下面的请求。
同步阻塞示例:
console.log(1000)
alert(200)
console.log(3000)
上面就是同步阻塞示例,你不点击alert确认窗口,不会打印3000
js绝大部分都是同步,不过多详解;
同步异步问题
首先,你要知道javascript是单线程
语言。js任务需要排队顺序执行,如果一个任务耗时过长,后边一个任务也的等着,但是,假如我们需要浏览新闻,但新闻包含的超清图片加载很慢,总不能网页一直卡着直到图片完全出来,所以将任务设计成了两类:
同步任务
异步任务
当我们打开网站时,网页的渲染过程就是一大堆同步任务,像页面骨架和页面元素的渲染,而加载图片、音乐之类的任务就是异步任务,看一下下边导图:
同步和异步任务分别进入不同的执行“场所”,同步进入主线程,异步进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入任务队列(Event Queue)。主线程内的任务执行完毕为空,就去任务队列(Event Queue)读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
但是,JS异步还有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入任务队列(event queue),然后再执行微任务,将微任务放入微任务队列(micro task queue),但是,这两个queue不是一个queue。当你往外拿的时候先从微任务队列里拿这个回调函数,然后再从宏任务的queue拿宏任务的回调函数,如下图:
任务列队和event loop(事件循环)
单线程就意味着,所有的任务都要排队,前一个结束,才会执行后面的任务。如果列队是因为计算量大,CPU忙不过来,倒也算了。但是更多的时候,CPU是闲置的,因为IO设备处理得很慢,例如
ajax读取网络数据。js设计者便想到,主线程完全可以不管IO设备,将其挂起,然后执行后面的任务。等后面的任务结束掉,在反过头来处理挂起的任务。
好,我们来梳理一下:
1)所有的同步任务都在主线程上执行,行成一个执行栈。
2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。
3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。
4)重复上面三步。
只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。
三、执行顺序
1.主线程上宏任务、微任务执行顺序
console.log('---start---');//第一轮主线程setTimeout(() => {console.log('setTimeout'); // 将回调代码放入个宏任务队列,第二轮宏任务执行
}, 0);new Promise((resolve, reject) => {console.log('---Promise第一轮微任务同步执行---');//第一轮微任务同步执行resolve()
}).then(()=>{console.log('Promise.then实例成功回调执行'); // 将回调代码放入微任务队列,第一轮宏任务执行完后立即执行
});console.log('---end---');//第一轮主线程结束
执行顺序:主线程 >> 主线程上创建的微任务 >> 主线程上创建的宏任务
2.宏任务中包含微任务
// 宏任务队列 1
setTimeout(() => {// 宏任务队列 2.1console.log('timer_1');setTimeout(() => {// 宏任务队列 3console.log('timer_3')}, 0)new Promise(resolve => {resolve()console.log('new promise')}).then(() => {// 微任务队列 1console.log('promise then')})
}, 0)setTimeout(() => {// 宏任务队列 2.2console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========')
执行顺序:主线程 >> 主线程上的宏任务队列1 >> 宏任务队列1中创建的微任务
========== Sync queue ==========1 timer_1
2 new promise
3 promise then
4 timer_2
5 timer_3
//请写出输出内容async function async1() {console.log('async1 start');await async2();console.log('async1 end');}async function async2() {console.log('async2');}console.log('script start');setTimeout(function() {console.log('setTimeout');}, 0)async1();new Promise(function(resolve) {console.log('promise1');resolve();}).then(function() {console.log('promise2');});console.log('script end');
这篇关于js异步之宏任务(marcroTask)和微任务(microTask)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!