JS事件循环机制
2020-09-22 20:36:14 0 举报
AI智能生成
js事件循环机制
作者其他创作
大纲/内容
浏览器中的EventLoop
js单线程机制
what
所有任务都在一个线程上完成
所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着
why
假定JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
为了避免复杂性,从一诞生,JavaScript 就是单线程,这已经成了这门语言的核心特征
how
js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,
一旦为空,就会去Event Queue(任务队列)那里检查是否有等待被调用的函数
一旦为空,就会去Event Queue(任务队列)那里检查是否有等待被调用的函数
任务分类
同步任务
同步任务进入主线程
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务
js异步机制
就是遇到宏任务,先执行宏任务,将宏任务放入宏任务队列
然后在执行微任务,将微任务放入微任务队列
当你往外拿的时候先从微任务队列拿这个回调函数并执行,然后再从宏任务的队列上拿宏任务的回调函数并执行
异步任务进入Event Table并注册回调函数
不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
宏任务(macrotask)
分类
setTimeOut
setInterval
setImmediate
I/O
callback
优先级
主代码块 > setImmediate > MessageChannel > setTimeOut/setInterval
特点
宏任务队列每次只会取出一条任务到执行栈中执行
requestAnimationFrame 在页面重绘前,当前微任务执行后再执行宏任务
先进先出
微任务(microtask)
分类
process.nextTick
Promise
MutationObserver
async(实质上也是promise)
优先级
process.nextTick > Promise > MutationOberser
特点
微任务队列操作,总是会一次性清空队列
浏览器会在一个宏任务结束后,检查是否有微任务开始执行
下一次宏任务,必须要等到当前微任务执行完毕,才可以执行
先进先出
执行分区
内存
执行栈
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件
一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,
于是结束等待状态,进入执行栈,开始执行
于是结束等待状态,进入执行栈,开始执行
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复
WebApi
ajax
events
mouse click
key press
scroll
network events
timing
。。。
异步回调队列
宏任务队列
宏任务总会在下一个EventLoop中执行
若在执行宏任务的过程中,加入了新的微任务,会把新的微任务添加到微任务的队列中
微任务队列
若在执行微任务的过程中,加入了新的微任务,会把新的微任务添加在当前任务队列的队尾
微任务会在本轮EventLoop执行完后,马上把执行栈中的任务都执行完毕
执行流程
Javascript内核加载代码到执行栈
执行栈依次执行主线程的同步任务,过程中若遇调用了异步Api则会添加回调事件到回调队列中。
且把微任务事件添加到微任务队列中,宏任务事件添加到宏任务队列中去。直到当前执行栈中代码执行完毕
且把微任务事件添加到微任务队列中,宏任务事件添加到宏任务队列中去。直到当前执行栈中代码执行完毕
开始执行当前所有微任务队列中的微任务回调事件
取出宏任务队列中的第一条(先进先出原则哦)宏任务,放到执行栈中执行
执行当前执行栈中的宏任务,若此过程总又再遇到微任务或者宏任务,继续把微任务和宏任务进行各自队伍的入队操作,
然后本轮的宏任务执行完后,又把本轮产生的微任务一次性出队都执行了
然后本轮的宏任务执行完后,又把本轮产生的微任务一次性出队都执行了
以上操作往复循环...就是我们平时说的eventLoop了
Node 环境中的EventLoop
渲染引擎
渲染引擎是多线程的,包含ui线程和js线程。ui线程和js线程会互斥,因为js线程的运行结果会影响ui线程,
ui更新会被保存在队列,直到js线程空闲,则被取出来更新
ui更新会被保存在队列,直到js线程空闲,则被取出来更新
运行机制
V8引擎解析JavaScript脚本
解析后的代码,调用Node API
libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎
V8引擎再将结果返回给用户
node任务队列
队列
timers(计时器队列)执行,setTimeout以及setInterval的回调
I/O callbacks(输入输出队列), 处理网络,流,TCP的错误 ,callback
idle, prepare,node内部调用
poll(轮询队列),执行poll中的i/o队列检查定时器是否到时
check(检查队列),存放setImmediate回调
close callbacks(关闭队列),如socket.on('close')
注意
这里的每一个阶段都对应着一个事件队列
当Event Loop进入到某个阶段的时候,就会将该阶段队列里的回调拿出来执行,直到队列为空
开始循环后,每次拿出当前阶段的全部任务执行,清空NextTick队列,清空微任务队列,再执行下一阶段,全部6个阶段完毕后,进入下一轮的循环
同步、异步,阻塞、非阻塞
同步
即为调用者等待被调用者这个过程,如果被调用者一直不反回结果,调用者就会一直等待,这就是同步,同步有返回值
异步
即为调用者不等待被调用者是否返回,被调用者执行完了就会通过状态、通知或者回调函数给调用者,异步没有返回值
阻塞
指当前线程在结果返回之前会被挂起,不会继续执行下去
非阻塞
即当前线程不管你返回什么,都会继续往下执行
0 条评论
下一页