事件循环:指的是JS执行异步代码的机制。
JS是单线程的。没有专门的用于处理异步代码的线程,而浏览器是多线程的;
JS的异步和多线程的实现是通过 Event Loop 事件循环机制来实现的。
所以,为了实现异步,浏览器为JS准备了一个队列,用于存放异步代码。这个队列叫做事件队列。
根据JS中的异步代码的性质,将异步代码分为了"宏任务代码"和"微任务代码"。
宏任务:setInterval、setTimeout、DOM事件函数、回调函数,ajax的回调;
微任务:Promise的then、catch、finally;但promise是同步任务;
执行栈(调用栈); 任务队列: 微任务,宏任务;
先执行同步代码;再执行微任务,等微任务都执行完了,再去执行宏任务,如果执行的宏任务里有微任务,再去执行微任务,执行完,再执行宏任务;直到任务队列里没有任务;
当代码执行的时候 会先把所有的全局代码放入执行栈然后开始从上往下 执行代码
遇见同步代码 立刻执行 然后执行下一条
遇见异步代码 立刻开启 然后执行下一条
直到执行栈清空
执行栈执行过程中,如果异步代码完成, 会将回调函数放入任务队列(定时器、延时器、事件函数、ajax的回调这些会进入宏任务队列排队;
then、catch、finally这三个会进入微任务队列排队)排队
等执行栈清空之后 ,会先从微任务队列中拿一个函数到执行栈中执行 ,执行完之后再去微任务队列中提取新的正在排队的函数, 直到微任务队列清空; 此时才会去宏任务队列中提取函数进入执行栈执行 ;
重复这个过程直到执行栈清空且任务队列清空,此时线程空闲下来
执行顺序:
先将所有的代码推入执行栈,一条一条执行。遇见异步代码就开启执行(仅仅是开启执行,什么时候推入任务队列参见上面说明)。直到执行栈清空。
清空执行栈后,去微任务队列中查找。
如果找得到,就将该函数放入执行队列中执行。执行完之后再去微任务队列中查找。重复此步骤,直至清空微任务队列。
至此执行栈清空,微任务队列清空。
查找宏任务队列,如果有就放入执行栈执行。执行完毕后,重复第2步至第5步
直至所有任务执行完毕
//输出的顺序是 同步代码,2; 微任务3,4; 宏任务1;
//2 3 4 1
setTimeout(function () {
console.log(1);
}, 0)
console.log(2);
var p = new Promise(function (resolve, reject) {
resolve();
})
p.then(function () {
console.log(3);
var p1 = new Promise(function (resolve, reject) {
resolve();
})
p1.then(function () {
console.log(4);
})
})