Evnt Loop即事件循环,是解决JavaScript单线程运行阻塞的一种机制。
堆(Heap)
堆表示一大块非结构化的内存区域。对象、数据被存在堆中
栈(Stack)
栈在JavaScript中又被称为执行栈、调用栈,是一种后进先出的数组结构。
JavaScript有一个主线程(main thread)和调用栈(call-stack或执行栈),主线各所有的任务都会被放到调用栈等待主线程执行。
JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移除,直到栈内被清空。
这里说的堆栈,是数据结构的堆栈,不是内存中的堆栈(内存中的堆栈,堆存放引用类型的数据,栈存放基本数据类型的数据)
function foo(b){
const a = 10;
return a + b + 11
}
function bar(x){
const y = 3;
return foo(x * y)
}
console.log(bar(7))
// 42
如上代码,当调用
bar
时,创建第一个帧,帧中包含了bar
的参数和局部变量。当bar
调用foo
时,第二个帧就被创建出来了,并被压到第一个帧之上,帧中包含了foo
的参数和局部变量。当foo
返回时,最上层的帧就被弹出栈(剩下bar
函数的调用栈)。当bar
返回时,栈就空了。
队列(Queue)
队列即任务队列(Task Queue),是一种先进先出的数据结构。在队尾添加新元素,从对头移除元素。
同步任务和异步任务
- 同步任务是调用立即得到结果的任务,同步任务在主线程上排队执行的任务,只有前一个任务执行完毕后,才能执行后一个任务。
- 异步任务是调用无法立即得到结果,需要额外的操作才能预期结果的任务,异步任务不进入主线程,而进入“任务队列”的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
js引擎遇到异步任务(DOM事件监听、网络请求、setTimeout计时器等),会交给相应的线程单独去维护异步任务,等待某个时机(计时器结束、网络请求成功、用户点击DOM),然后由事件触发线程将异步对应的回调函数加入到消息队列中,消息队列中的回调函数等待被执行。
异步运行机制
- 所有同步任务都在主线程上执行,形成一个执行栈
- 主线程之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列之中放置一个事件。
- 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面第三步。
主线程从任务队列中读取事件,这个过程是不断循环的,所以整个的这种运行机制又被称为Evnt Loop(事件循环)
宏任务和微任务
所有任务分为宏任务(macrotask)和微任务(microtask)两种。
- 宏任务包括
script
全部代码、setTimeout
、setInterval
、setImmediate
、I/O
、UI Rendering
。 - 微任务包括
Process.nextTick
、Promise
、Object.observe
(废弃)、MutationObserver
在挂起任务时,JS引擎会将所有任务按照类别分到两个队列中,首先在宏任务的队列中取出第一个任务,执行完毕后取出微任务队列中的所有任务顺序执行,之后再取宏任务,周而复始,直至两个队列的任务都取完。
异步编程的几种方法:
- 回调函数
- 事件监听
- 发布/订阅
- Promise对象
- Generator函数
- async/awai
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 chaoyumail@126.com