什么是宏任务和微任务
宏任务包括: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
任务列队和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.1
console.log('timer_1');
setTimeout(() => {
// 宏任务队列 3
console.log('timer_3')
}, 0)
new Promise(resolve => {
resolve()
console.log('new promise')
}).then(() => {
// 微任务队列 1
console.log('promise then')
})
}, 0)
setTimeout(() => {
// 宏任务队列 2.2
console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========')
执行顺序:主线程 >> 主线程上的宏任务队列1 >> 宏任务队列1中创建的微任务
注意:
new promise
中的打印为同步,.then
为微任务。
如果有两个宏任务,并且第一个宏任务里有微任务和宏任务,执行顺序是:
第一个宏任务的所有同步 ---->> 第一个宏任务的所有微任务 ---->> 第二个宏任务的同步 ---->>第一个宏任务的宏任务
面试题:
console.log( '1' );
async function async1() {
console.log( '2' );
await async2();
console.log( '3' );
}
async function async2() {
console.log( '4' );
}
setTimeout( function () {
console.log( '5' );
new Promise( function ( resolve ) {
console.log( '6' );
resolve();
} ).then( function () {
console.log( '7' )
} )
} )
async1();
new Promise( function ( resolve ) {
console.log( '8' );
resolve();
} ).then( function () {
console.log( '9' );
} );
console.log( '10' );
// 1 2 4 8 10 3 9 5 6 7