Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event Loop #2

Open
SinLv opened this issue Jun 15, 2020 · 0 comments
Open

Event Loop #2

SinLv opened this issue Jun 15, 2020 · 0 comments

Comments

@SinLv
Copy link
Owner

SinLv commented Jun 15, 2020

前言

Event Loop即事件循环,是指浏览器或Node的一种解决JavaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

堆、栈、队列

image

堆(Heap)

堆时一种数据结构,时利用完全二叉树维护的一组数据,堆分为两种,一种为最大堆,一种为最小堆,将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆是线性数据结构,相当于一维数组,有唯一后继。

如最大堆
image

栈(Stack)

栈在计算机科学中是限定在表尾进行插入或删除操作的线性表。栈式一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。
栈是只能在某一端插入和删除的特殊线性表。

image

队列(Queue)

特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。
进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出

image

Event Loop

在JavaScript中,任务被分为两种,一种宏任务(MacroTask),一种叫微任务(MicroTask).

MacroTask(宏任务)

  • script全部代码、setTimeout、setInterval、setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/O、UI Rendering。

MicroTask(微任务)

  • Process.nextTick(Node独有)、Promise、Object.observe(废弃)、MutationObserver(具体使用方式查看这里)

浏览器中的Event Loop

JavaScript有一个主线程和调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。

JS调用栈

JS调用栈采用的时后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。

同步任务和异步任务

JavaScript单线程任务被分为同步任务异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

image

任务队列是一种先进先出的一种数据结构。

image

事件循环的进程模型

  • 选择当前要执行的任务队列,选择任务队列中最先进入的任务,如果任务队列为空即null,则执行跳转到微任务的执行步骤。
  • 将事件循环中的任务设置为已选任务。
  • 执行任务。
  • 将事件循环中当前运行任务设置为null。
  • 将已经运行完成的任务从任务队列中删除。
  • microtasks步骤:进入microtask检查点。
  • 更新界面渲染。
  • 返回第一步。

执行进入microtask检查点时,用户代理会执行以下步骤

  • 设置microtask检查点标志为true。
  • 当事件循环microtask执行不为空时:选择一个最先进入的microtask队列的microtask,将事件循环的microtask设置为已选择的microtask,运行microtask,将已经执行完成的microtask为null,移出microtask中的microtask。
  • 清理IndexDB事务
  • 设置进入microtask检查点的标志为false

执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务队列是否为空,如果为空的话,就执行宏任务,否则就一次性执行完所有微任务。
每次单个宏任务执行完后,检查微任务队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务后,设置微任务队列为null,然后再执行宏任务,如此循环。

举个例子

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});
console.log('script end');

首先我们划分几个分类:

第一次执行:

Tasks:run script、 setTimeout callback

Microtasks:Promise then	

JS stack: script	
Log: script start、script end。

执行同步代码,将宏任务(Tasks)和微任务(Microtasks)划分到各自队列中。

第二次执行:

Tasks:run script、 setTimeout callback

Microtasks:Promise2 then	

JS stack: Promise2 callback	
Log: script start、script end、promise1、promise2

执行宏任务后,检测到微任务队列中不为空,执行Promise1,执行完成Promise1后,调用Promise2.then,放入微任务队列中,再执行Promise2.then。

第三次执行:

Tasks:setTimeout callback

Microtasks:	

JS stack: setTimeout callback
Log: script start、script end、promise1、promise2、setTimeout

当微任务队列中为空时,执行宏任务,执行setTimeout callback,打印日志。

第四次执行:

Tasks:setTimeout callback

Microtasks:	

JS stack: 
Log: script start、script end、promise1、promise2、setTimeout

清空Tasks队列和JS stack。

NodeJS的Event Loop

image

Node中的Event Loop是基于libuv实现的,而libuv是Node的新跨平台抽象层,libuv使用异步,事件驱动的编程方式,核心是提供i/o的事件循环和异步回调。libuv的API包含有时间,非阻塞的网络,异步文件操作,子进程等。

image

Node的Event Loop一共分为6个阶段,每个细节具体如下:

  • timers:执行setTimeout和setInterval中到期的callback。
  • pending callback:上一轮循环中少数的callback会放在这一阶段执行。
  • idle,prepare:仅在内部使用。
  • poll:最重要的阶段,执行pending callback,在适当情况下会阻塞在这个阶段。
  • check:执行setImmediate(setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成后之后立即执行setImmediate指定的回调函数)的callback。
  • close callbacks:执行close事件的callback,例如socket.on('close'[, fn])或者http.server.on('close', fn)。
@SinLv SinLv closed this as completed Jun 26, 2020
@SinLv SinLv reopened this Aug 17, 2020
@SinLv SinLv changed the title 实现简单的节流和防抖 Event Loop Aug 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant