首页 > 编程语言 >JavaScript 事件循环

JavaScript 事件循环

时间:2024-09-09 15:36:06浏览次数:11  
标签:style -- button JavaScript transform 任务 循环 事件 div

0x01 事件循环

  • JavaScript 是单线程的,即同一时间内仅能执行一个操作

  • 在单线程中,当一段代码中存在需要等待或触发的任务时,会阻塞线程,影响后续代码的执行,因此需要将代码分为同步异步,其执行过程如下:

    flowchart LR 代码--同步-->JS引擎-->执行栈--立即执行-->执行栈 代码--异步-->s[宿主环境<br/>如浏览器或NodeJS]--触发事件-->任务队列 执行栈--查看是否有异步任务-->任务队列--获取异步任务-->执行栈

    异步编程方法详见《JavaScript 异步编程 | 博客园-SRIGT》

  • 在上述执行过程中,执行栈反复向任务队列查看并获取任务的过程,称为事件循环

0x02 宏任务与微任务

  • JavaScript 的异步任务又分为宏任务微任务
    • 宏任务由宿主环境发起,如 AjaxfetchsetTimeoutsetInterval<script>、事件等
    • 微任务由 JS 引擎发起,如 async/await Object.observeprocess.nextTickPromisethencatch 回调方法等
  • 任务队列分为宏任务队列和微任务队列
  • 在事件循环中,优先执行所有微任务,之后执行宏任务

0x03 requestAnimationFrame

  • 在事件循环中,分为执行渲染两步

    • 对于以下代码,事实上仅最后一句有效

      button.addEventListener("click", () => {
        div.style.display = "none";
        div.style.display = "block";
        div.style.display = "none";
        div.style.display = "block";
        div.style.display = "none";
      });
      

      因为所有逻辑代码都执行后才会进入渲染,而非每次变化都会进行渲染

  • 所有同步和异步代码均在执行阶段

    • 如同步代码 while(true){} 在执行阶段会阻塞后续渲染,而递归则不会阻塞
  • Chromium 提供的 requestAnimationFrame(简称 rAF)方法允许代码在渲染阶段的渲染前执行

  • 举例:方块先右移 1000px,再左移 500px

    1. 页面元素与样式

      <body>
        <div style="width: 100px; height: 100px; background-color: black;"></div>
        <div style="width: 500px; height: 5px; background-color: aqua;"></div>
        <button>开始</button>
        <script>
          // JavaScript 逻辑代码
        </script>
      </body>
      
    2. JavaScript 逻辑代码

      const div = document.querySelector("div");
      const button = document.querySelector("button");
      button.addEventListener("click", () => {
        div.style.transform = "translateX(1000px)";
        div.style.transition = "transform 2s ease-in-out";
      
        requestAnimationFrame(() => {
          div.style.transform = "translateX(500px)";
        });
      });
      

      此时方块只会右移 500px,并不符合要求
      因为完成执行进入渲染时,先执行 rAF,后渲染,因此此时的代码相当于:

      const div = document.querySelector("div");
      const button = document.querySelector("button");
      button.addEventListener("click", () => {
        div.style.transform = "translateX(1000px)";
        div.style.transition = "transform 2s ease-in-out";
        div.style.transform = "translateX(500px)";
      });
      
    3. 解决方法:

      const div = document.querySelector("div");
      const button = document.querySelector("button");
      button.addEventListener("click", () => {
        div.style.transform = "translateX(1000px)";
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            div.style.transition = "transform 2s ease-in-out";
            div.style.transform = "translateX(500px)";
          });
        });
      });
      

-End-

标签:style,--,button,JavaScript,transform,任务,循环,事件,div
From: https://www.cnblogs.com/SRIGT/p/18404675

相关文章

  • 循环计数器/循环栅栏/循环屏障 CyclicBarrier
    CyclicBarrier和CountDownLatch有点类似,主要区别是CyclicBarrier可以重用,常用方法如下:CyclicBarrierbarrier=newCyclicBarrier(3);//表示条件为:要有3个线程达到屏障(未指定屏障动作)barrier.await();//如果没有3个线程到达屏障,当前线程就阻塞,直到有3个线程达到......
  • [Javascript] Function.prototype.call
    .callmethodexitsonanyfunction,whichwillreferto Function.prototype.callforexample:console.log.call===Function.prototype.call//call AlsoitmeansthatFunction.prototype.call===Function.prototype.call.call Question:console.log.call.cal......
  • GIS大事件!Bentley收购Cesium
    9月6日,Cesium官方宣布加入Bentley。Bentley我们并不陌生。最初Acute3D被Bentley公司收购,旗下软件由Smart3DCapture转型到ContextCapture,现又改名iTwinCapture。如今又收购了Cesium。Cesium官方表示,Cesium开发平台与iTwin的结合将为自然和建筑环境数字孪生的构建提供了完......
  • 【洛谷 P1996】约瑟夫问题 题解(数组+模拟+循环)
    约瑟夫问题题目描述个人围成一圈,从第一个人开始报数,数到的人出列,再由下一个人重新从开始报数,数到的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰名小朋友,而该题是全部出圈。输入......
  • JavaScript 函数式编程
    0x01函数式编程(1)概述函数式编程(FunctionalProgramming,简称FP)是一种编程范式,它将计算机运算视为数学上的函数计算,强调将计算过程看作是函数之间的转换而不是状态的改变❗“函数”的意思是指映射关系其他常见编程范式包括面向过程编程、面向对象编程等核心思想:将函......
  • JavaScript操作DOM节点
    1.操作DOM2.节点和节点的关系3.访问节点3.1使用getElement系列方法访问指定节点getElementById()、getElementsByName()、getElementsByTagName()3.2根据层次关系访问节点节点属性属性名称描述parentNode返回节点的父节点childNodes返回子节点集合,childNodes[i]fir......
  • C++学习笔记(曾经我看不懂的代码2:基于范围的for循环、auto使用、stl容器、template模
    不知不觉c++程序设计:标准库已经看了一大半了,学到了很多,很多曾经在网上和在书上看到却看不懂的代码,在看完标准库中的大半内容以后,都能大致的理清代码的含义。代码模板一:for(auto&a:arr)1、基于范围的for循环:a为迭代变量,arr为迭代范围,&表示引用。写一个例子:#include<ios......
  • 51nod 1050 循环数组最大子段和
    51nod1050循环数组最大子段和虽然是板子题,两种做法,我们先写一种,另一个咕咕。因为是循环,所以分为两种,中间的和两边的,中间的直接dp求最大,两边的转化一下就是总的数字和减去中间的最小数字和。#include<bits/stdc++.h>usingnamespacestd;#definelllonglonglla[500005]......
  • 14、Flink SQL 的 事件时间详解
    事件时间事件时间允许程序按照数据中包含的时间来处理,这样可以在有乱序或者晚到的数据的情况下产生一致的处理结果,它可以保证从外部存储读取数据后产生可以复现(replayable)的结果。事件时间可以让程序在流式和批式作业中使用同样的语法,在流式程序中的事件时间属性,在批式程......
  • 【JavaScript系列八】—讲述JS学习历程的知识分享!
    前言本篇主要讲述JS中较为重要的一环,函数的用法,深拷贝和浅拷贝的概念和区别,闭包和递归,包括一些案例:例如递归实现斐波那契数列,求阶乘等等一、关于函数定义函数的方式function关键字函数表达式(匿名函数)varfn=function(){}newfunction()函数的调用及其this指向普通函数—......