js的事件循环机制以及操作dom为什么代价大、耗能高

JS为什么是单线程的,多线程不香么?

原因是,并行操作可能会使系统对dom节点的改动发生冲突(可以参考操作系统的互斥部分)。比如同时对一个dom节点进行增加和删除,那该怎么办呢?没法干,容易出事
为了利用多核CPU的计算能力,h5提出web worker标准,允许js脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。新标准没有改变js单线程的本质。

同步任务与异步任务

同步任务,顾名思义,就是立即执行的任务,同步任务一般会直接进入到主线程中执行;而异步任务,就是异步执行的任务,比如ajax网络请求,setTimeout 定时函数等都属于异步任务,异步任务会通过任务队列( Event Queue )的机制来进行协调。事件循环呢,其实就是在同步任务与异步任务的交替执行中形成的。

console.log('script start');
setTimeout(function() {
 console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
 console.log('promise1');
}).then(function() {
 console.log('promise2');
});
console.log('script end');

试着去理解一下,这个答案是 script start、script end 、promsie1、promise2、setTimeout
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。
在事件循环中,每进行一次循环操作称为tick,通过阅读规范可知,每一次 tick 的任务处理模型是比较复杂的,其关键的步骤可以总结如下:
在此次 tick 中选择最先进入队列的任务( oldest task ),如果有则执行(一次)
检查是否存在 Microtasks ,如果存在则不停地执行,直至清空Microtask Queue
更新 render
主线程重复执行上述步骤
// 具体的运行方法需要从宏任务和微任务的角度去理解
https://www.cnblogs.com/yugege/p/9598265.html(原文)

减少dom操作,代价大、耗性能

DOM其实就是一个js对象,每个dom节点就是这个对象里面的属性。因此,操作dom其实就是修改js对象的属性值,这个js对象改变以后,会触发浏览器的一些行为,这个行为(layout和paint)就是代价大、耗性能的源头了。
layout就是布局变动造成重新计算(耗cpu,有时也耗内存);paint就是调用浏览器UI引擎进行渲染展示页面(耗cpu和内存)

浏览器不会蠢到对于每次操作都马上回应,它是lazy的。

对于css和js都会把layout行为的数据缓存到一个队列中,当上下文完成执行后进行一次layout(css:结点的样式描述完 js:一个代码块执行完)
浏览器的lazy会带来一个问题,layout信息在队列中的时候,我所需要获取dom节点信息就获取不到了。这时浏览器就会提前执行一次layout,造成了dom操作耗性能耗资源的局面(代价比较大的原因)
特别提出,动画的每一帧都会导致layout,动画元素要绝对定位,脱离文档流。
dom操作太过频繁会怎么样呢?手机端会因为内存爆满或cpu占用过度而出现浏览器闪退现象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值