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
    评论
`Vue.nextTick`是Vue提供的一个API,它可以让我们在DOM更新之后执行一些操作。在Vue中,当数据发生变化时,Vue会异步执行DOM更新操作。也就是说,当我们修改了Vue实例中的某个属性,Vue并不会立即去更新DOM,而是先将这个更新操作加入到一个队列中,在下一个事件循环时,Vue会清空这个队列,依序执行其中的更新操作。 由于Vue的异步更新机制,有时候我们需要在DOM更新之后执行一些操作,比如获取更新后的DOM节点的尺寸或位置等。此时,我们就可以使用`Vue.nextTick`来确保这些操作是在DOM更新后执行的。 下面是一个使用`Vue.nextTick`的例子: ```javascript new Vue({ el: '#app', data: { message: 'Hello Vue.js!' }, methods: { updateMessage: function () { this.message = 'Updated!' this.$nextTick(function () { // DOM已经更新 console.log(this.$el.textContent) // "Updated!" }) } } }) ``` 在`updateMessage`方法中,我们首先修改了`message`属性的值,然后调用了`this.$nextTick`方法,在回调函数中打印了`this.$el.textContent`。由于`this.$nextTick`方法会在DOM更新之后执行回调函数,所以打印出来的是更新后的内容。 需要注意的是,`Vue.nextTick`不是立即执行的,而是在下一个事件循环时执行的。这意味着如果我们在某个方法中多次调用`Vue.nextTick`,那么这些回调函数会被加入到同一个队列中,在下一个事件循环时一起执行。这个特性可以帮助我们避免不必要的DOM操作,从而提性能。 总的来说,`Vue.nextTick`可以帮助我们更好地掌控Vue的异步更新机制,避免出现一些奇怪的bug。同时,它也为我们提供了一个优化性能的机会,让我们能够更好地利用Vue的异步更新机制

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值