事件循环

 
 
 
事件循环机制(Event Loop)
 
JavaScript引擎是单线程,也就是说每次只能执行一项任务,其他任务都得按照顺序排队等待被执行,只有当前的任务执行完成之后才会执行下一个任务。
 
任务 分为同步任务和异步任务
 
同步任务:
var t = Date.now();
console.log('Hi');
 
异步任务:
setTimeout(function() { console.log(‘b’); }, 0)
dom.onclick = function (){...}
 
调用栈与事件队列
 
调用栈 Call Stack
是一种后进先出的数据结构。当一个脚本执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入调用栈中,然后从头开始执行。
 
事件队列 Task Queue
js引擎遇到一个异步任务后并不会一直等待其返回结果,而是会将这个任务交给浏览器的其他模块进行处理(以webkit为例,是webcore模块),继续执行调用栈中的其他任务。当一个异步任务返回结果后,js引擎会将这个任务加入与当前调用栈不同的另一个队列,我们称之为事件队列。
 
 
当一个脚本执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入调用栈中,然后从头开始执行。
 
js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起(其他模块进行处理),继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入到事件队列。
 
被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这个过程被称为“事件循环(Event Loop)”。
 
实例:
console.log(1);
var t = setTimeout(function() {
    console.log(2);
}, 0)
var promise = new Promise(function(resolve, reject) {
    console.log(3);
    resolve();
})
promise.then(function() {
    console.log(4);
})
console.log(5);
 
 
 
以上的事件循环过程是一个宏观的表述,实际上因为异步任务之间并不相同,因此他们的执行优先级也有区别。
不同的异步任务被分为两类:微任务(micro task)和宏任务(macro task)。
macro-task:setTimeout、setInterval......
micro-task:Promises、Object.observe......
 
在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。
根据这个异步事件的类型,实际上会被放到宏任务队列或者微任务队列。
当前调用栈执行完毕时会优先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。
 
 
 
这样就能解释上面那段代码的结果,为什么4先于2被打印出来了!
 
 简单来说就是:三个空间,调用栈+异步代码执行模块空间+任务队列(微任务,宏任务),调用栈先执行,异步代码在另个一个模块执行,执行完后在队列中等待,微任务先执行回调,宏任务后执行回调。
 
 
posted @ 2021-03-03 23:30  不想飞的小鸟  阅读(82)  评论(0编辑  收藏  举报