微任务和宏任务有哪些
- 宏任务:
setTimeOut
,setInterval
,Ajax
,DOM事件
- 微任务:
promise
,async/await
微任务比宏任务执行时机早
例如:
console.log(100)
setTimeout(() => {
console.log(200)
})
Promise.resolve().then(() => {
console.log(300)
})
console.log(400)
结果:
// 100 400 300 200
为什么微任务比宏任务执行时机早?
首先需要去了解下eventLoop和DOM渲染
:
call stack
空闲(同步代码执行完毕)或者call stack
清空(每次轮询结束)- 尝试渲染
DOM
( 不一定非得渲染,就是给一次 DOM 渲染的机会!!! ) - 触发
event-loop
代码示例:
const $p1 = $('<p>一段文字</p>')
const $p2 = $('<p>一段文字</p>')
const $p3 = $('<p>一段文字</p>')
$('#container')
.append($p1)
.append($p2)
.append($p3)
console.log('length', $('#container').children().length )
alert('本次 call stack 结束,DOM 结构已更新,但尚未触发渲染')
// (alert 会阻断 js 执行,也会阻断 DOM 渲染,便于查看效果)
// 到此,即本次 call stack 结束后(同步任务都执行完了),浏览器会自动触发渲染,不用代码干预
// 另外,按照 event loop 触发 DOM 渲染时机,setTimeout 时 alert ,就能看到 DOM 渲染后的结果了
setTimeout(function () {
alert('setTimeout 是在下一次 Call Stack ,就能看到 DOM 渲染出来的结果了')
})
结果:
- 首先可以看到,container.children的长度为3,但是页面上还没有渲染。
-DOM渲染了,setTimeOUt也执行了
宏任务和微任务的区别
宏任务
:DOM 渲染后
再触发微任务
:DOM 渲染前
会触发
// 修改 DOM
const $p1 = $('<p>一段文字</p>')
const $p2 = $('<p>一段文字</p>')
const $p3 = $('<p>一段文字</p>')
$('#container')
.append($p1)
.append($p2)
.append($p3)
// 微任务:渲染之前执行(DOM 结构已更新)
Promise.resolve().then(() => {
const length = $('#container').children().length
alert(`micro task ${length}`)
})
// 宏任务:渲染之后执行(DOM 结构已更新)
setTimeout(() => {
const length = $('#container').children().length
alert(`macro task ${length}`)
})
- 先执行了微任务:
Promise
-DOM渲染之后,执行了宏任务 setTimeout
再深入思考一下:为何两者会有以上区别,一个在渲染前,一个在渲染后?
这是因为:
-
微任务:ES 语法标准之内,JS 引擎来统一处理。即,不用浏览器有任何关于,即可一次性处理完,更快更及时。
-
宏任务:ES 语法没有,JS 引擎不处理,浏览器(或 nodejs)干预处理。
总结
微任务,宏任务,DOM渲染,在Event-loop里的关系:
- 先执行同步代码,知道
call stack
空闲 - 执行
micro task queue(微任务队列)
里面的事件 - 尝试
DOM渲染
- 触发
event-loop
执行callBack queue
队列里面的事件