setTimeout(
function() {
console.log('1')
}, 2000
)
setTimeout(
function() {
console.log('2')
}, 500
)
let p = new Promise((resolve, reject)=>{
console.log('3')
resolve('本身是同步操作,异步返回')
})
setTimeout(
function() {
console.log('4')
p.then(res => {
console.log('444444', res)
})
}, 500
)
let p1 = new Promise((resolve, reject)=>{
console.log('5')
resolve('数据')
})
async function fn1() {
await p1;
console.log('6')
}
fn1()
let p2 = new Promise((resolve, reject)=>{
console.log('7')
resolve('数据22222')
})
p2.then(res=> {
console.log('8')
}
console.log('9')
输出:
3
5
7
9
6
8
2
4
4444 本身是同步操作,异步返回
1
async function fn1 (){
console.log(1)
await fn2()
console.log(2) // 阻塞 相当于微任务
}
async function fn2 (){
console.log('fn2')
}
fn1()
console.log(3)
上面的例子中,await 会阻塞下面的代码(即加入微任务队列),先执行 async外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码
所以上述输出结果为:1,fn2,3,2
js 是单线程, 先执行主程序任务 ,
主线程执行结束之后 才执行异步操作,异步操作包含宏任务和微任务;
在执行主程序的过程时候 ,如果遇到宏任务则先把它放到宏任务队列中,如果遇到微任务则放到微任务队列中,
主程序结束之后,先执行 微任务,等微任务结束之后,(开启下一个事件循环)再去宏任务队列中取宏任务,
在执行宏任务的过程中可能会遇到微任务,放到微任务队列,
等到这个宏任务结束,取微任务队列任务执行。微任务结束之后,(开启下一个事件循环) 再去 宏任务队列取下一个任务 ,以此重复,直到结束.....
宏任务: script(整体代码) , setTimout, setInterval, setImmediate, I/O DOM事件(比如点击事件),异步Ajax请求
;
微任务: process.nexttick, promise.then / .catch /.finally, await阻塞的代码相当于微任务,MutationObserver, Object.observe(废弃)
UI渲染是在微任务之后,下次宏任务之前;
<script>
$('#container').append('<div>p1</div>').append('<div>p2</div>').append('<div>p3</div>')
alert('主程序任务') //DOM没渲染
// 宏任务:DOM渲染后触发
setTimeout(() => {
console.log('length2', $('#container'))//3
alert('setTimeout')//DOM 渲染了
}, 5000);
// 微任务: DOM渲染前触发
Promise.resolve().then(() => {
console.log('length1', $('#container'))//3
alert('Promise then') //DOM没渲染
});
</script>
学习参考: