事件循环 Event Loop 
浏览器为了协调同步和异步任务制定的一种工作机制,主线程先依次执行同步任务,同步任务中有一些异步回调,将其推入到任务队列中
宏任务与微任务 
宏任务 Macro-Task 
宿主环境(运行 JS 的环境,例如浏览器)提供的叫宏任务,主要包括创建⽂档对象、解析HTML、执⾏主线JS代码以及各种事件如⻚⾯加载、输⼊、⽹络事件和定时器等
微任务 Micro-Task 
语言标准(例如ECMA)提供的叫微任务,微任务的例⼦有 Promise 回调函数、DOM变化等。
执行顺序为:一个宏任务 =》所有微任务 =》下一个宏任务,可以点此体验一下
requestAnimationFrame 
window.requestAnimationFrame() 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行,也属于异步执行的方法,但是该方法既不是宏任务,也不是微任务
事件循环的过程 
- 执行完同步任务
- 检查 microtask queues微任务队列是否为空,非空则到第 3 步,为空到第 4 步
- 执行 microtask queues微任务队列中的所有任务
- 检查 macrotask queues宏任务队列是否为空,非空则到第 5 步,为空到第 6 步
- 取出 macrotask queues中的一个任务,在执行栈执行,执行完成后返回到第 2 步
- 执行视图更新
以 Promise 与 setTimeout 举例,执行以下代码:
js
Promise.resolve().then(() => {
    console.log('Promise1');
    setTimeout(() => {
        console.log('setTimeout2');
    }, 0);
});
setTimeout(() => {
    console.log('setTimeout1');
    Promise.resolve().then(() => {
        console.log('Promise2');
    });
}, 0);上述代码的输出结果为:Promise1 -> setTimeout1 -> Promise2 -> setTimeout2,其事件循环过程如下所示:
- 一开始执行栈的同步任务执行完毕,检查微任务队列
- 清空微任务队列 ,此时输出 Promise1,并将setTimeout2放入宏任务队列,此时宏任务队列中任务是 [setTimeout1,setTimeout2]
- 从宏任务队列中取出第一个任务执行,输出 setTimeout1,并将Promise2放入微任务队列,此时微任务队列中任务是 [Promise2]
- 接着又检查并清空微任务队列,输出 Promise2
- 再次清空 microtask queues后查询宏任务队列[setTimeout2],取出第一个任务执行,,输出setTimeout2