JavaScript事件原理

 
  • 事件循环(消息循环)
    • 事件循环是基于浏览器主线程的
    • Js是一门单线程语言,其执行在浏览器的主线程上
    • 浏览器不是只有单线程的
    • Js若所有程序都在一个线程上执行,则浏览器必然会发生阻塞现象,故而有异步执行来解决Js的单线程同步问题
    • 换一个角度来说,Js是一门基于浏览器的多线程语言
    • 主线程的Js代码执行会影响页面的渲染 => 主线程上执行延时死循环时,只有其循环结束后才会执行其他代码,包括对页面的渲染工作
    • 浏览器的任务没有优先级先后之说,但是执行过程中产生的不同的任务队列却有优先级先后
    • 任务队列分为宏任务和微任务,而宏任务因为不能满足浏览器的任务安排需求,故而又被分解成很多其他任务队列(延时队列交互队列网络响应队列等),因此浏览器的任务队列分为微任务队列和其他任务队列(宏任务分解的那些队列)
    • 每个任务都有对应的任务类型,同类型的任务必须在同一个队列,不同类型的任务可以分属于不同的队列
    • 事件循环调度每次将从优先级最高的队列中取出第一个任务进行执行(不是取出整个队列的任务加入到主线程)
    • 在执行过程中生成的异步线程会在合适的时候(对应线程执行完成后)将任务加入到对应类型的队列尾部

      单线程时异步产生的原因,事件循环是异步的实现方式

  • 页面构建时间线
    1. 创建document对象,开始解析web页面。解析HTML元素和他们的文本内容后添加element对象和text节点到文档中。这阶段document.readystate="logading"
    2. 遇到link的外部css,创建线程加载,并继续解析文档。
    3. 遇到script外部js,并且没有设置async、defer,浏览器加载,并阻塞,等技术加载完成并执行该脚本,然后继续解析文档。
    4. 遇到script外部js,并且设置async、defer,浏览器创建线程加载,并继续解析文档。对于async属性的脚本,脚本加载完成后立即执行。(异步加载禁用documen.write())
    5. 遇到img等,先正常解析dom结构,然后浏览器异步加载src,并继续文档
    6. 当文档解析完成,document。readystate=“interactive”。
    7. 文档解析完成后,所以设置有defer的脚本会按照顺序执行。(注意与async的不同,但同样禁止使用document.write())
    8. document对象触发DOMContentLoaded事件,这也标志着程序执行从听听不脚本执行阶段,转化为事件驱动阶段。
    9. 当async的脚本加载完成并执行后,img等加载完成后,document.readystate=“complete”,window对象触发load事件。
    10. 从此,以异步相应方式处理用户输入、网络事件。