JTangming / blog

My repository on GitHub.
Other
53 stars 0 forks source link

JavaScript运行机制 & Event Loop #12

Open JTangming opened 5 years ago

JTangming commented 5 years ago

参考文章

JTangming commented 5 years ago

event loop

结合以下描述,看图理解。

JTangming commented 4 years ago

JavaScript 是单线程、非阻塞的脚本语言,单线程指同一个时间只能做一件事。

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

而非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。

JavaScript 的任务分两种:一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

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

理解 Event Loop

JavaScript 的运行机制如下:

主线程不断重复上面的第三步。所以整个的这种运行机制又称为 Event Loop(事件循环)。只要主线程空了,就会去读取"事件队列",这就是 JavaScript 的运行机制。

事件队列包括:Task Queue 和 MicroTask Queue

javascript 代码运行分两个阶段:

微任务(Microtask)与宏任务(Macrotask)

异步任务分为宏任务和微任务,宏任务队列可能有多个,而微任务队列只有一个:

以上仅仅讲了大致的执行流程,下面结合微任务和宏任务细说一下执行 JavaScript 代码的具体流程:

tips:执行宏任务的过程中,遇到微任务,依次加入微任务队列,会在下一次微任务中被执行。如果在执行 microtask 的过程中,又产生了 microtask,那么会加入到队列的末尾,会在当前这个周期被调用执行。

event loop-2

JTangming commented 4 years ago

浏览器为了能够使得 JS 内部 Macrotask 与 DOM 任务能够有序的执行,会在一个 Macrotask 执行结束后,在下一个 Macrotask 执行开始前切换至 UI 线程,对页面进行重新渲染,流程如下:

(macro)task->渲染->(macro)task->...

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

JTangming commented 3 years ago

node环境下的事件循环机制

事件循环的模型:

┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<──connections───     │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

node中事件循环的实现是依靠的libuv引擎。

chrome v8 引擎将 js 代码解释后去调用对应的 node api,而这些 api 最后由libuv引擎驱动,执行对应的任务,并把不同的事件放在不同的队列中等待主线程执行。

因此实际上 node 中的事件循环存在于 libuv 引擎中。

Reference:

JTangming commented 3 years ago

全方位解读前端用到的栈结构(调用栈、堆、垃圾回收等)