什么是 EventLoop
JavaScript 的事件分两种,宏任务和微任务
宏任务(macrotask,新标准中叫task):
包括整体代码 script(整体代码) 、 setTimeout 、setInterval、setImediate
微任务(microtask,新标准中叫jobs):Promise.then(非 new Promise)、process.nextTick(node中)、MutationObserver(html5新特性)
事件的执行顺序 :先执行宏任务,然后执行微任务,任务有同步的任务和异步的任务,同步的任务进入主线程,异步的进入 Event Table并注册函数,异步事件完成后,会将回调函数放在队列中,如果还有异步的宏任务,那么就会进行事件循环执行上述的操作。
同步任务:在主线程上排队执行的任务,,只有前一个任务执行完毕,才能执行后一个任务
异步任务:不进入主线程,而进入任务队列(task quene)的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
宏任务和微任务示例
// 1.宏任务 - 异步
setTimeout(() => {
//执行后 回调一个宏事件
console.log('1')
}, 0)
// 2.宏任务 - 同步
console.log('2');
// 3.宏任务 - 同步
new Promise((resolve) => {
console.log('3');
resolve()
}).then(() => {
// 4.微任务 - 异步
console.log('4');
}).then(() => {
// 5.微任务 - 异步
console.log('5')
})
// 2.宏任务 - 同步
console.log('6')
// print results : 2 3 6 4 5 1
async function async1() {
// 1.宏任务-异步
console.log("1")
await async2();
// 2.微任务-异步
console.log("2")
}
// 3.宏任务-异步
async function async2() {
console.log("3")
// return promise对象
}
// 4.宏任务-同步
console.log("4")
// 5.宏任务-异步
setTimeout(function () {
console.log("5")//最后执行
}, 0)
async1()
// 6.宏任务-同步
new Promise(function (resolve) {
console.log("6")
resolve()
}).then(function () {
// 7.微任务-异步
console.log("7")
})
// 8.宏任务-同步
console.log("8")
//print results:4 1 3 6 8 2 7 5
总结:事件循环先执行宏任务,其中同步任务立即执行,异步任务加载到对应的 Event quene 中,微任务也加载到对应的 Event quene 中,所有的同步微任务执行完之后,如果发现微任务的 Event quene 中有未执行完的任务,先执行他们。这样就算完成了一轮事件循环。接下来查看宏任务的队列中是否有异步代码,有的话执行第二轮的事件循环,以此类推。
setTimeout、Promise、async/await的区别
setTimeout 的回调函数放到宏任务队列里,属于宏任务中的异步任务,等到执行栈清空以后执行
Promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行
async 方法执行时,遇到 await 会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
栈、堆、队列?(补充了解)
栈和堆的区别
栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收堆(数据结构):堆可以被看成是一颗树,如堆排序。栈(数据结构):一种先进后出的数据结构
栈和队列的区别
栈的插入和删除操作都是在一端进行的,而队列的操作确是在两端进行的队列先进先出,栈先进后出栈只允许在一端进行插入和删除,而队列允许在一端进行插入,在另一端进行删除