-
堆(Heep)
- 堆是一种数据结构,是利用二叉树维护的一组数据,堆分为两种,一种为最大堆,一种为最小堆,将根节点最大的堆称之为最大堆或大根堆,根节点最小的堆,叫做最小堆或者小根堆,堆是线性数据结构,相当于一维数组,有唯一后继
-
栈(Stack)
- 栈,是在计算机科学中限定仅在表尾进行插入,或者是删除操作的线性表,栈是一种数据结构,它按照后进先出的原则存储数据,
先进入的数据压入栈底
,最后的数据在栈顶
,需要读数据的时候,从栈顶开始弹出数据,栈是只能在某一端插入和删除的特殊线性表
- 栈,是在计算机科学中限定仅在表尾进行插入,或者是删除操作的线性表,栈是一种数据结构,它按照后进先出的原则存储数据,
-
队列(Queue)
-
队列,其特殊之处在于,只允许在表的前端(front)进行删除操作,而在表尾(rear)进行插入操作,和堆栈一样,是一种受限的线性表,进行插入操作的端,叫做队尾,进行删除操作的端,叫做队头,队列中不存在元素时,称之为空队列
-
队列的数据元素,称之为队列元素,在队列中
插入一个队列元素,称之为入队,
从队列中删除一个元素,称之为出队,
因为队列只允许在一端插入,在另外一端删除,所以只有最早进入队列的元素,才能从队列中删除,故队列称之为先进先出
-
-
宏任务(MacroTask)
script
全部代码、setTimeout
、setInterval
、setImmediate
(浏览器暂时不支持,只有IE10支持,具体可见MDN
)、I/O
、UI Rendering
-
微任务(MicroTask)
Process.nextTick(Node独有)
、Promise
、Object.observe(废弃)
、MutationObserver
-
浏览器中的EventLoop
Javascript
有一个main thread
主线程和call-stack
调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行
-
js调用栈
- JS调用栈采用的是
后进先出
的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空
- JS调用栈采用的是
-
同步任务和异步任务
Javascript
单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行
- 任务队列
Task Queue
,即队列,是一种先进先出的一种数据结构
-
事件循环的事件模型
- 选择当前要执行的任务队列,选择任务队列中最先进入的任务,如果任务队列为空即
null
,则执行跳转到微任务(MicroTask
)的执行步骤。 - 将事件循环中的任务设置为已选择任务。
- 执行任务。
- 将事件循环中当前运行任务设置为null。
- 将已经运行完成的任务从任务队列中删除。
- microtasks步骤:进入microtask检查点。
- 更新界面渲染。
- 返回第一步。
- 选择当前要执行的任务队列,选择任务队列中最先进入的任务,如果任务队列为空即
-
执行栈进入microtask检查点时,用户代理会执行以下步骤
-
设置microtask检查点标志为true。
-
当事件循环
microtask
执行不为空时:选择一个最先进入的microtask
队列的microtask
,将事件循环的microtask
设置为已选择的microtask
,运行microtask
,将已经执行完成的microtask
为null
,移出microtask
中的microtask
。 -
清理IndexDB事务
-
设置进入microtask检查点的标志为false
-
执行栈在执行完同步任务以后,查看执行栈是否为空,如果执行栈为空,就会去执行
task(宏任务)
每次宏任务执行完毕以后,检查是否存在微任务(microTask)
队列是否为空,如果不为空的话,会按照先进先出
的规则全部执行完毕微任务(microTask)
后,设置微任务(microTask)
队列为null
然后再去执行宏任务,如此循环,就形成了事件循环(EventLoop)
-
-
举个栗子
-
请说出以下代码输出的结果
console.log('1'); setTimeout(function() { console.log('2'); }, 0); // resolve是一个同步任务,后面虽然调用了then方法,但是执行顺序还是先去执行同步任务,然后再去执行异步任务 Promise.resolve().then(function() { console.log('3'); }).then(function() { console.log('4'); }); console.log('5'); // 1 5 3 4 2
-
-
第一次执行
- (执行同步代码,将
宏任务(Task)
和微任务(Microtasks)
划分到各自的队列中)
Tasks:run script、 setTimeout callback Microtasks:Promise then JS stack: script Log: script start、script end。
- (执行同步代码,将
-
第二次执行
- 执行宏任务后,检测到微任务(
Microtasks
)队列中不为空,执行Promise1
,执行完成Promise1
后,调用Promise2.then
,放入微任务(Microtasks
)队列中,再执行Promise2.then
Tasks:run script、 setTimeout callback Microtasks:Promise2 then JS stack: Promise2 callback Log: script start、script end、promise1、promise2
- 执行宏任务后,检测到微任务(
-
第三次执行
- 当微任务(
Microtasks
)队列中为空时,执行宏任务(Tasks
),执行setTimeout callback
,打印日志
Tasks:setTimeout callback Microtasks: JS stack: setTimeout callback Log: script start、script end、promise1、promise2、setTimeout
- 当微任务(
-
第四次执行
- 清空Tasks队列和
JS stack
Tasks:setTimeout callback Microtasks: JS stack: Log: script start、script end、promise1、promise2、setTimeout
- 清空Tasks队列和