首页 > 解决方案 > Why do two codes perform differently?

问题描述

Why do the following two codes perform differently? There is only one difference between the two ends of the code which part 2 has a setTimeout

// 1
var div = document.querySelector('.move');
div.classList.add('start');
div.classList.add('move-active');
requestAnimationFrame(() => {
  div.classList.remove('start');
  div.classList.add('end');
});
div.style.display = 'block';
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>test</title>
  <style>
    .move {
      position: absolute;
      width: 100px;
      height: 100px;
      background-color: red;
    }
    
    .start {
      transform: translateX(0);
    }
    
    .move-active {
      transition: transform 3s ease;
    }
    
    .end {
      transform: translateX(100px);
    }
  </style>
</head>

<body>
  <div class="move" style="display: none;"></div>
</body>

</html>
// 2
setTimeout(() => {
  var div = document.querySelector('.move');
  div.classList.add('start');
  div.classList.add('move-active');
  requestAnimationFrame(() => {
    div.classList.remove('start');
    div.classList.add('end');
  });
  div.style.display = 'block';
}, 0); 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>test</title>
  <style>
    .move {
      position: absolute;
      width: 100px;
      height: 100px;
      background-color: red;
    }
    
    .start {
      transform: translateX(0);
    }
    
    .move-active {
      transition: transform 3s ease;
    }
    
    .end {
      transform: translateX(100px);
    }
  </style>
</head>

<body>
  <div class="move" style="display: none;"></div>
</body>

</html>

  1. In the first part of the code, each browser refresh will have animation effect
  2. But in the second part of the code, each browser refresh will have animation effect

Why does setTimeout have different effects on the same code? Isn't setTimeout putting the whole code block in the event loop thread and then executing it in the JS engine thread?

标签: javascripthtml

解决方案


I tried your code and in both cases, most of the time the animation was not there. But sometimes, when the stars align, there was an animation of the Redbox moving from left to right.

I think this is dependent on the request animation call and pure luck instead of your usage of setTimeout. If the callback of requestAnimationFrame function is called on the next repaint after the Redbox has been painted, then the animation will be there otherwise not.

You can, however, make this behavior more reliable using the setTimeout function. Below is an example using your code.

setTimeout(() => {
    var div = document.querySelector('.move');
    div.classList.add('start');
    div.classList.add('move-active');
    setTimeout(function () {
      requestAnimationFrame(() => {
        div.classList.remove('start');
        div.classList.add('end');
      });
    }, 0);
    div.style.display = 'block';
}, 0);
.move {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: red;
}
.start {
  transform: translateX(0);
}
.move-active {
  transition: transform 3s ease;
}
.end {
  transform: translateX(100px);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>test</title>
</head>
<body>
    <div class="move" style="display: none;"></div>
</body>
</html>

setTimeout will delegate the requestAnimationFrame function call to the next event loop cycle. At that time, requestAnimationFrame will delegate the callback to the next repaint. This should, in most cases, remove the start class and add the end class to the element after it has been painted resulting in the animation taking place.


推荐阅读