JavaScript是一种单线程语言,有同步和异步的概念,这就解决了代码阻塞的问题
同步任务:是直接放在主线程上排队依次执行,
异步任务:会放在任务队列中,若有多个异步任务则需要在任务队列中排队等待,任务队列类似于缓冲区,任务下一步会被移到调用栈然后主线程执行调用栈的任务。
浏览器的事件循环
在事件驱动的模式下,至少包含了一个执行循环来检测任务队列中是否有新任务。通过不断循环,去取出异步任务的回调来执行,这个过程就是事件循环,每一次循环就是一个事件周期。
浏览器的事件循环由一个宏任务队列+多个微任务队列组成。
首先,执行第一个宏任务:全局 Script 脚本。产生的的宏任务和微任务进入各自的队列中。执行完 Script 后,把当前的微任务队列清空。完成一次事件循环。接着再取出一个宏任务,同样把在此期间产生的回调入队。再把当前的微任务队列清空。以此往复。宏任务队列只有一个,而每一个宏任务都有一个自己的微任务队列,每轮循环都是由一个宏任务+多个微任务组成。
宏任务和微任务
任务队列其实不止一种,根据任务种类的不同,可以分为微任务(micro task)队列和宏任务(macro task)队列。常见的任务如下:
宏任务: script( 整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)
微任务: Promise、MutaionObserver、process.nextTick(Node.js 环境);
例子
setTimeout(() => {
//setTimeout(1)
console.log(0);
}, 0);
new Promise((res) => setTimeout(res, 0)//setTimeout(2)
).then(() => {
console.log(1);
setTimeout(() => {
console.log(2); //setTimeout(3)
}, 0);
new Promise((r => r())).then(() => {
console.log(3); //promise(2)
});
});
setTimeout(() => {
console.log(4); //setTimeout(4)
}, 0);
new Promise((res) => res()).then(() => {
console.log(5); //promise(1)
});
1.setTimeout(1),setTimeout(2),setTimeout(4)分别放入宏任务队列
2.promise(1)放入微任务队列
3.执行微任务队列,输出 5
4.微任务队列清空,执行setTimeout(1)输出0 ,执行setTimeout(1),promise(2)放入微任务队列,setTimeout(3)放入宏任务队列
5.执行同步任务输出1 微任务队列执行,输出3
6.微任务队列清空,执行宏任务队列setTimeout(4),setTimeout(3) 输出 4 2
结果:5 0 1 3 4 2
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
Promise.resolve()
.then(function () {
console.log('promise1')
})
.then(function () {
console.log('promise2')
})
console.log('script end')
1.执行同步任务 输出 script start,script end
2.setTimeout放入宏任务队列,Promise放入微任务队列
3.执行微任务队列,输出 promise1,promise2
4.微任务队列清空,执行setTimeout输出setTimeout
结果:script start,script end,promise1,promise2,setTimeout
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')
1.执行同步任务script start,输出script start,setTimeout放入宏任务队列
2.执行async1(),输出 async1 start,执行async2(),输出async2,await后面放入微任务队列,执行promise,输出promise1
3.promise放入微任务队列,输出同步任务script end
4.执行微任务队列,输出async1 end,promise2
5.清空微任务队列,执行宏任务队列,输出setTimeout
结果:script start,async1 start,async2,promise1,script end,async1 end,promise2,setTimeout