JavaScript基础篇06:事件和JS执行机制

事件

  1. 什么是宏任务和微任务?

    • 宏任务是由宿主发起的任务,包括:script(外层同步代码)、window.setTimeout()window.setInternal()window.requestAnimationFrame()(要求浏览器在下次重绘之前调用指定的回调函数更新动画)、setImmediate ()(Node.js) ,最常见的是script和定时器。

    • 微任务是由JavaScript引擎发起的任务,包括:Promise状态改变后的回调函数、MutationObserver(监视DOM树的变化,变化时调用回调函数) 等等,最常见的微任务是Promise状态改变后的回调函数。

      微任务产生于宏任务的执行期间,只有在当前JS执行栈为空时才会执行微任务。

      当前宏任务产生的微任务永远先于下一个宏任务前执行,执行微任务期间,当前宏任务并未完全结束。

    举个例子:小明去银行办理业务,叫号轮到小明时,柜员开始为小明办理他的主要业务(宏任务),主要业务办理完毕后(执行栈为空),柜员询问小明是否还有其他业务需要办理(查询微任务队列是否有微任务),柜员为小明办理其他业务(微任务),全部办理完毕后才会轮到下一位叫号(下一宏任务)。

  2. 什么是事件循环(event loop)?

    event loop是JavaScript执行机制中的一环,它的作用在于调控执行机制,确定下一个需要执行的任务

    它的每一次循环称为一次tick循环过程如下:

    • 当前宏任务执行完毕后,若执行栈为空,判断微任务队列中是否存在需要执行的微任务
    • 执行所有微任务
    • 如果宿主为浏览器,判断是否有必要渲染页面
    • 执行下一个宏任务,开始新一轮tick

    要注意,真正执行任务的是JavaScript的主线程执行栈,event loop只是起到一个发号施令的作用。

image.png

  1. JavaScript的执行机制是什么?

    1. JavaScript引擎是单线程的,同一时间段只能执行一个任务

      浏览器是多线程的,其主要线程包括:

      • GUI渲染线程

        负责渲染页面,解析HTML、CSS,构建DOM树,绘制页面等等;

        页面重绘和回流;

        与JS引擎互斥,即JS执行时会阻塞页面更新。

      • JS引擎线程

        是JavaScript的内核,负责JavaScript代码的执行。

      • 事件触发线程(event table)

        用于控制事件循环,管理任务队列;

        当遇到事件绑定或者异步操作时,事件触发线程会将它们添加到对应的线程中进行处理,有了处理结果以后,事件触发线程会将回调函数添加到任务队列,等待JS引擎线程处理

        事件触发线程并不执行任务,只是负责跟踪任务,并及时将它们推进任务队列。

      • 定时器线程 setTimeout()setInterval()所处的线程就是定时器线程,由于JavaScript引擎线程是单线程的,所以需要单独线程来计时并触发定时。

      • 异步http请求线程

        负责执行异步请求。

    2. 首先,最外层的script会作为第一个宏任务开始执行。

      当遇到同步代码时,推入主线程执行栈执行;遇到异步代码时,判断其属于宏任务还是微任务;

      将异步任务推给事件触发线程(event table),即在主线程内,这些任务属于被挂起的状态,而在事件触发线程内,异步任务会被推进相应线程处理,并注册回调函数;

      异步任务有了处理结果后,事件触发线程会将它们推进任务队列(event quene),宏任务推进宏任务队列(tasks quene),微任务推进微任务队列(microtasks quene);

      第一个宏任务执行完毕后,会进入事件循环(event loop),JS引擎会执行事件循环指示的任务,直到执行栈和所有队列都为空。

      image.png

  2. 什么是事件冒泡和事件捕获?

    事件流描述了页面接收事件的顺序,IE和Netscape提出了两种完全相反的事件流模型,分别是事件冒泡和事件捕获。

    • 事件冒泡:事件被定义为由最具体的那个元素触发,逐级向上传播至没有那么具体的元素(文档)。现代浏览器都支持事件冒泡,且事件会一直冒泡到window对象。
    • 事件捕获:最不具体的节点最先收到事件,而最具体的节点最后收到事件。事件捕获是为了在事件到达最终目标之前拦截事件。

    DOM2规范中规定了事件流包括三个阶段:事件捕获、到达目标和事件冒泡

    DOM2的事件处理程序方法element.addEventListener(event, function, useCapture)的第三个参数useCapture是一个布尔值,为true时表示在捕获阶段调用事件处理程序,为false时表示在冒泡阶段调用事件处理程序,默认值为false.

  3. 什么是事件委托(事件代理)?

    • 首先要弄明白什么是事件对象

      事件对象是能够传给事件处理程序的唯一参数,其常见的属性和方法包括:

      • type(返回被触发事件类型的字符串)
      • target(事件目标)
      • currentTarget(当前事件处理程序的所在元素)
      • stopPropagation()(阻止事件冒泡)
      • preventDefault()(阻止默认事件)
      • 等等。
    • 事件委托的原理不是给每个子节点都设置事件监听器,而是给父节点设置事件监听器,利用冒泡原理影响每个子节点。

    • 使用事件委托可以减少事件处理函数来做到性能优化,但是事件委托一定涉及对子节点和父节点的控制,因此在事件处理函数中要善用事件对象的各个属性和方法。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享