setTimeout(fn, 0) // it works - JavaScript 事件循环 动画演示

settimeout,fn,it,works,javascript,事件,循环,动画,演示 · 浏览次数 : 14

小编点评

**事件循环** 事件循环是一种异步执行机制,它允许浏览器同时处理多个 JavaScript 脚本,从而提高网页的性能。事件循环在 JavaScript 中使用 setTimeout 或 setInterval 函数实现。 **setTimeout(fn, 0)** `setTimeout(fn, 0)` 函数用于在指定时间后执行一个函数。但是,如果 `0` 被传递给 `setTimeout`,则函数将立即执行。 **事件循环示例** ```javascript setTimeout(() => { console.log('Hello, world!'); }, 0); ``` 这个代码将打印「Hello, world!」在 3 秒后执行。 **事件循环与 setTimeout 的区别** | 特性 | 事件循环 | setTimeout | |---|---|---| | 执行顺序 | 异步 | 同步 | | 延迟时间 | 可设置 | 默认 0 | | 最终执行函数 | 当事件循环结束后执行 | 当指定的定时器到期时执行 | **事件循环的优点** * 提高网页性能 * 允许处理多个 JavaScript 脚本 * 减少渲染阻塞 **事件循环的缺点** * 可能导致渲染阻塞 * 难以管理异步操作 * 需要在 JavaScript 代码中添加大量的延时操作 **结论** `setTimeout(fn, 0)` 是一个用于异步执行函数的 JavaScript 方法。虽然 `0` 默认值会导致函数立即执行,但它可以用于指定延迟时间后执行函数。事件循环是一种强大的机制,可以用于构建高效的 JavaScript 应用。

正文

在前端代码中很经常看到使用 setTimeout(fn, 0),如下面代码所示,乍一看很多余,但是移除了可能会出现一些奇奇怪怪的问题。要解释这个就需要理解 事件循环(Event Loop),下面会通过一些例子和动画来辅助理解事件循环

setTimeout(() => {
  // 调用一些方法
}, 0)

为什么使用事件循环

JS 是单线程的(浏览器和 Node则是多线程的),为了避免 渲染主线程 阻塞,需要异步,事件循环 是异步的实现方式

浏览器在一个渲染主线程中运行一个页面中的所有 JavaScript 脚本,以及呈现布局,回流,和垃圾回收。为了避免 同步 的执行方式导致渲染主线程阻塞,使得页面卡死,所以浏览器采用异步的方式:渲染主线程将任务交给其他线程去处理,自身 立即结束 任务的执行,转而执行后续代码,当其他线程完成时,将事先传递的回调函数包装成任务,加入到对应的消息队列的末尾排队,等待渲染主线程调度执行

流程:

  1. 渲染主线程执行全局 JS,需要异步的任务放到对应的队列,如果是 setTimeout 则会有线程计时,到了指定时间会将任务放入 延时队列(并非立即执行)
  2. 渲染主线程为空时,按队列的优先级依次选择队列(最先执行微队列的任务),依次按顺序执行各个队列的任务

任务没有优先级,而消息队列有优先级,不同任务分属于不同队列:参考 W3C 规范微队列优先级最高,接着是交互队列然后才是延时队列

常见队列:

  • 微队列(microtask):⽤户存放需要最快执⾏的任务,优先级「最⾼」,通过 Promise.resolve().then() ⽴即把⼀个函数添加到微队列
  • 交互队列:⽤于存放⽤户操作后产⽣的事件处理任务,优先级「⾼」
  • 延时队列:⽤于存放计时器到达后的回调任务,优先级「中」

事件循环

下面例子来自于:《WEB前端大师课》,大块的文字描述相对没那么直观,所以用 Keynote 做了 gif 方便理解(如果有更好的做 gif 的方式可以留言告诉我)

1. JS阻碍页面渲染

JS 修改了 DOM 后,并不会马上显示在页面上,需要进行 绘制 后才会显示页面变更

<!DOCTYPE html>
<html lang="en">
  <head></head>
  <body>
    <h1>初始h1</h1>
    <button>change</button>
    <script>
      var h1 = document.querySelector('h1');
      var btn = document.querySelector('button');

      function delay(duration) {
        var start = Date.now();
        while (Date.now() - start < duration) {}
      }
      
      btn.onclick = function () {
        h1.textContent = '修改h1 textContent';
        delay(3000);
      };
    </script>
  </body>
</html>

01绘制任务

效果:点击 change 后,页面卡死,3s 后 h1 内容变更为:修改h1 textContent

2. 延迟队列

setTimeout 到达指定时间可能并不会立即执行

setTimeout(function () {
  console.log(1);
}, 0);

function delay(duration) {
  var start = Date.now();
  while (Date.now() - start < duration) {}
}

delay(3000);

console.log(2);

02settimeout

效果:卡死 3s 后输出 2 1

3. 微队列

使用 Promise.resolve().then 可以将任务直接添加到微队列

setTimeout(function () {
  console.log(1);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});

console.log(3);

03微队列

效果:依次输出 3 2 1

4. 复杂情况

function a() {
  console.log(1);
  Promise.resolve().then(function () {
    console.log(2);
  });
}
setTimeout(function () {
  console.log(3);
  Promise.resolve().then(a);
}, 0);

Promise.resolve().then(function () {
  console.log(4);
});

console.log(5);

04复杂Promise

效果:依次输出 5 4 3 1 2

拓展

理解了上面的概念,可以尝试分析一下 现代 JavaScript 教程 事件循环例子,检查一下是否理解了事件循环

参考资料

2024 年我还在写这样的代码
为什么 JS 要加入 setTimeout, css 的 transition 才能生效
深入理解和使用 Javascript 中的 setTimeout(fn,0)
主线程
并发模型与事件循环
异步 JavaScript
调度:setTimeout 和 setInterval

与setTimeout(fn, 0) // it works - JavaScript 事件循环 动画演示相似的内容:

setTimeout(fn, 0) // it works - JavaScript 事件循环 动画演示

在前端代码中很经常看到使用 setTimeout(fn, 0),如下面代码所示,乍一看很多余,但是移除了可能会出现一些奇奇怪怪的问题。要解释这个就需要理解 事件循环(Event Loop),下面会通过一些例子和动画来辅助理解事件循环 setTimeout(() => { // 调用一些方法 }, 0

关于async/await、promise和setTimeout执行顺序

前段时间领导给我们出了一道题,关于async/await、promise和setTimeout的执行顺序,网上查了查资料,这是头条的一道笔试题,记录一下,加深理解。 题目如下: async function async1() { console.log('async1 start'); await

如何优雅的实现动画效果

1.实现动画的方式 javaScript:setTimeout、setInterval css3: transition、animation html: canvas requestAnimationFrame Api 前三种我们都很熟悉,重点说说requestAnimationFrame 2.re

js定时器

一.定时器 1. JS存在两种定时器 setTimeout() 延迟定时器 setInterval() 循环定时器(“间隔器”) 定时器中的函数挂载在window对象,内部的this ——> window setTimerout(function(){ console.log('wuwei') },

Vue源码学习(九):响应式前置:实现对象的依赖收集(dep和watcher)

好家伙,这是目前为止最绕的一章,也是十分抽象的一章 由于实在太过抽象,我只能用一个不那么抽象的实例去说服我自己 完整代码已开源https://github.com/Fattiger4399/analytic-vue.git 1.我们要做什么? 来看这个例子, index.html setTimeou