EventLoop 事件循环机制

前言

JavaScript是单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。

Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

在这里插入图片描述

任务队列

一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue),任务队列"是一个先进先出的数据结构.
只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。
那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

常见宏任务(普通任务队列和延迟队列中的任务都属于宏任务。):渲染事件、js脚本执行、用户交、网络请求、文件读写完成事件等等。互事件

微任务的引入

其实引入微任务的初衷是为了解决异步回调的问题。

常见的微任务有MutationObserver、Promise.then(或.reject) 以及以 Promise 为基础开发的其他技术(比如fetch API), 还包括 V8 的垃圾回收过程。

定时器

除了放置异步任务的事件,"任务队列"还可以放置定时事件,定时器功能主要由setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行。以下主要讨论setTimeout()。

问题:setTimeout设置的秒数一定精准吗?
答案:不准确!因为要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
理解:setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。另一个原因:刷新频率受屏幕分辨率和屏幕尺寸的影响,因此不同设备的屏幕刷新频率可能会不同,而 setTimeout只能设置一个固定的时间间隔,这个时间不一定和屏幕的刷新时间相同。

问题;怎么实现一个精准的计时?
利用请求动画帧requestAnimationFrame实现

优点:
- 最大的优势是由系统来决定回调函数的执行时机,它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次
- CPU节能
-  函数节流

参考:
深入理解 requestAnimationFrame

猜你喜欢

转载自blog.csdn.net/HZ___ZH/article/details/110958662
今日推荐