我们来谈谈JavaScript中的事件循环(Event Loop)。
什么是事件循环?
事件循环是JavaScript的一个重要的运行机制,它使得浏览器的JavaScript引擎具备操作系统调度器的功能。它不断地从任务队列中取出任务执行,直到任务队列为空。
JavaScript的事件循环是一个持续进行的过程,所以它被称为循环。而任务的来源有两种,一种是来自于浏览器内部,另一种是来自于JavaScript自己。
任务队列
任务队列分为两种:macro task(宏任务) 和 micro task(微任务)。
宏任务包括script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI rendering等。当宏任务队列中的任务执行完成后,事件循环才会去执行微任务队列。
微任务包括process.nextTick、Promise、Object.observer等。
在任务队列中,任务是按照先进先出(FIFO)的顺序执行的。
事件循环执行流程
事件循环的执行流程一般是这样的:
- 执行整体代码(Script)。
- 执行所有宏任务(macro task)。每个宏任务的执行过程都要从头到尾完成,中途不能被打断。
- 执行所有微任务(micro task)。每个微任务的执行过程都必须瞬间执行完成,不会存在异步等待的情况。
- 进行UI渲染,更新界面。
整个过程会重复执行,直到没有更多的任务需要执行。
下面我们通过两个示例来更好的理解事件循环。
示例一
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise');
});
console.log('script end');
执行上述代码,输出结果如下:
script start
script end
promise
setTimeout
解析:
- 执行整体代码(Script),输出
script start
。 - 执行
setTimeout
,由于是宏任务,将该任务放置到宏任务队列中,等待执行。 - 执行
Promise
的then
回调,将该任务放置到微任务队列中,等待执行。 - 输出
script end
。 - 此时微任务队列中的任务已经全部执行完毕,事件循环开始执行宏任务队列中的任务,先执行
setTimeout
,输出setTimeout
。
示例二
console.log('script start');
setTimeout(function() {
console.log('setTimeout1');
Promise.resolve().then(function() {
console.log('promise inside setTimeout1');
});
}, 0);
setTimeout(function() {
console.log('setTimeout2');
Promise.resolve().then(function() {
console.log('promise inside setTimeout2');
});
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
执行上述代码,输出结果如下:
script start
script end
promise1
promise2
setTimeout1
promise inside setTimeout1
setTimeout2
promise inside setTimeout2
解析:
- 执行整体代码(Script),输出
script start
。 - 执行两个
setTimeout
,将它们放置到宏任务队列中,等待执行。 - 执行
Promise
的第一个then
回调,将任务添加到微任务队列中,等待执行。 - 执行
console.log('script end')
。 - 执行微任务队列中的任务,输出
promise1
,开始执行下一个then
回调。 - 输出
promise2
。 - 此时微任务队列已经执行完毕,事件循环开始执行宏任务队列,优先执行第一个
setTimeout
中的微任务:输出promise inside setTimeout1
。 - 接下来继续执行第一个
setTimeout
中的宏任务,输出setTimeout1
。 - 执行第二个
setTimeout
,将其放置到宏任务队列中等待执行。 - 接着我们又在第一个
setTimeout
的微任务队列中添加了一个任务:输出promise inside setTimeout2
。 - 执行第二个
setTimeout
中的宏任务,输出setTimeout2
。 - 事件循环结束,UI线程进行渲染。
希望上述两个示例可以帮助理解JavaScript中的事件循环机制。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:简单聊聊JavaScript中的事件循环 - Python技术站