前端笔记【1】

163 阅读5分钟

什么是事件委托?

js的事件流分为3个阶段:捕获、目标、冒泡。即事件来了,先从上到下传播(捕获),到达目标节点(目标),然后在往上传播(冒泡)。 就是利用冒泡的原理 把加事件加到父级上,触发执行效果。

  • 事件捕获和事件冒泡机制
  1. 事件捕获
  • 当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件
  1. 冒泡
  • 当事件到达目标节点后,会沿着捕获阶段的路线原路返回。同样,所有经过的节点,都会触发对应的事件

  • 事件委托的优点:

  1. 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
  2. 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。

window的onload事件和domcontentloaded谁先谁后?

  • load整个页面加载后会触发该事件,包括所有相关资源,如样式表图像。这与之相反DOMContentLoaded,只要加载页面DOM就会触发,而不等待资源完成加载。
  • domcontentloaded快比windowonload快

宏任务微任务

  • 事件循环
  1. 同步任务和异步任务分别进入不同的执行场所,同步的进去主线程,异步的进入enent table并注册函数。
  2. 当指定的事情完成时,event table会将这个函数移步到 event queue
  3. 主线程的任务执行完毕为空,会去event queue读取对应的函数,进入主线程执行
  4. 上诉过程会不断重复,也就是常说的event loop(事件循环)
  • 那怎么知道主线程的执行栈为空啊?
  • 原因是:js引擎存在monitoringprocess进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去event queue那里检查是否用等待被调用的函数。
  • 事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。
  • setTimeout通常设定时间执行,不过实际它的执行时间是异步的,当主线程的任务执行完毕为空,会去eventqueue读取对应的函数,进入主线程执行。
  • 又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着,导致真正的延迟时间远远大于设定时间。
  • setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。
  • 对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入EventQueue,如果前面的任务耗时太久,那么同样需要等待。
  • 唯一需要注意的一点是,对于setInterval(fn,ms)来说,我们已经知道不是每过ms秒会执行一次fn,而是每过ms秒,会有fn进入EventQueue。一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了。

经典面试题

for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); }; 结果是?
  • 结果:1 秒之后,同时输出 5 个 5。
  1. 因为for循环会先执行完(同步优先于异步优先于回调),这时五个 setTimeout 的回调全部塞入了事件队列中,然后 1 秒后一起执行了。
  2. 因为 setTimeout的console.log(i);的i是var定义的,所以是函数级的作用域,不属于for循环体,属于 global。
  3. 等到 for 循环结束,i 已经等于 5 了, 这个时候再执行 setTimeout的五个回调函数,里面的console.log(i); 的i 去向上找作用域,只能找到 global下 的 i,即 5。所以输出都是 5。
  • 解决方法:
  1. 人为给console.log(i); 创造作用域,保存i的值,即闭包。
  2. let 替换 var,let 声明的变量只在它所在的代码块有效。 上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。
  3. 如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 0-4。
  • for循环的计数器,就很合适使用let命令。 javascript是一门单线程语言,在最新的HTML5中提出了Web-Worker,但javascript是单线程这一核心仍未改变。
  • 所以一切javascript版的"多线程"都是用单线程模拟出来的,一切javascript多线程都是纸老虎!