Reputation: 167
I am trying to make a loader animation style for my website. The loading animation is 16 bars which increase and decrease in order. For example, the first bar will increase and then decrease back to its original size. Then the next bar will repeat this process until all bars have done it, then stop the process and reveal the page. In this case, because JavaScript is asynchronous on calling functions, I used a promise to get around it. The use of promise is to animate the bar after the previous has completed animating. Currently, my code animates only the first bar and stops there. It doesn't continue to animate the rest of them. Below are all of my codes:
IMPORTANT! The issue it on javascript. Don't spend time on HTML or CSS.
var index = -1;
function loading(){
var loader = document.getElementById("loader");
display = window.getComputedStyle(loader).display;
if (display == "block"){
var child = document.getElementById("loader-ul").getElementsByTagName("div");
index = index + 1;
alert("dd");
animate(child);
}
}
function animate(element){
var el = element[index];
var MaxHeight = false;
var finished = false;
function anim(){
return new Promise(function(resolve, reject){
if (finished == false){
if (MaxHeight == false){
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height + 1;
Bot = Bot + 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height <= 100){
window.requestAnimationFrame(anim);
}
else{
MaxHeight = true;
}
}
if (MaxHeight == true){
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height - 1;
Bot = Bot - 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height >= 50){
window.requestAnimationFrame(anim);
}
else{
MaxHeight = true;
finished = true;
el.style.bottom = 0 + "px";
el.style.height = 50 + "px";
}
}
}
else{
resolve();
}
});
}
anim().then(loading);
}
body{
margin: 0px;
padding: 0px;
margin: auto;
}
#loader{
display: block;
position: fixed;
height: 100%;
width: 100%;
background-color: white;
z-index: 9999;
}
#loader .center{
position: relative;
height: 50px;
width: 200px;
background-color: red;
top: 50%;
transform: translateY(-50%);
margin: auto;
}
#loader .center div{
width: 2px;
height: 50px;
background-color: blue;
float: left;
padding: 0px;
margin-right: 5px;
margin-bottom: 25px;
position: relative;
}
<body onload="loading()">
<div id="loader">
<div class="center" id="loader-ul">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</body>
I also have a link to jsfiddle:
https://jsfiddle.net/6227jjen/
Thank you all!
Note: I have added some alerts for debugging purposes.
Upvotes: 2
Views: 273
Reputation: 664528
Calling window.requestAnimationFrame(anim);
will never resolve your promise. It will call anim
which will create another promise which might then get resolved if you're finished, but the original promise is never fulfilled.
Instead of wrapping the whole body of anim
in a new Promise
constructor, you should promisify only requestAnimationFrame
and then use that to build a promise chain.
function animate(element){
var el = element[index];
var MaxHeight = false;
var finished = false;
function getFrame() {
return new Promise(function(resolve) {
window.requestAnimationFrame(resolve);
});
}
function anim(){
if (finished == false){
if (MaxHeight == false){
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height + 1;
Bot = Bot + 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height <= 100){
return getFrame().then(anim);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
} else{
MaxHeight = true;
}
}
if (MaxHeight == true){
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height - 1;
Bot = Bot - 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height >= 50){
return getFrame().then(anim);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
} else{
MaxHeight = true;
finished = true;
el.style.bottom = 0 + "px";
el.style.height = 50 + "px";
}
}
}
return Promise.resolve();
}
return anim().then(loading);
}
Upvotes: 0
Reputation: 1643
The problem is that not all path leads to resolve. The bigger problem is that your code creates a lot of promises instead of one. Here is the outline of the change.
function anim () {
return new Promise (function (resolve) {
function _anim () {
if (!finished) {
_logic();
// By putting requestAnimationFrame at the end, you can ensure
// that it will be called after your logic
// (assuming finished eventually equals true).
window.requestAnimationFrame(_anim);
}
else
resolve();
}
});
Here is the actual fix.
var index = -1;
function loading() {
var loader = document.getElementById("loader");
display = window.getComputedStyle(loader).display;
if (display == "block") {
var child = document.getElementById("loader-ul").getElementsByTagName("div");
index = index + 1;
alert("dd");
animate(child);
}
}
function animate(element) {
var el = element[index];
var MaxHeight = false;
var finished = false;
function anim() {
return new Promise(function(resolve, reject) {
function _anim() {
if (finished == false) {
if (MaxHeight == false) {
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height + 1;
Bot = Bot + 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height > 100) {
MaxHeight = true;
}
}
if (MaxHeight == true) {
var height = parseInt(window.getComputedStyle(el).height.slice(0, -2));
var Bot = parseFloat(window.getComputedStyle(el).bottom.slice(0, -2));
height = height - 1;
Bot = Bot - 0.5;
el.style.bottom = Bot + "px";
el.style.height = height + "px";
if (height < 50) {
MaxHeight = true;
finished = true;
el.style.bottom = 0 + "px";
el.style.height = 50 + "px";
}
}
window.requestAnimationFrame(_anim);
} else {
resolve();
}
}
_anim();
});
}
anim().then(loading);
}
body {
margin: 0px;
padding: 0px;
margin: auto;
}
#loader {
display: block;
position: fixed;
height: 100%;
width: 100%;
background-color: white;
z-index: 9999;
}
#loader .center {
position: relative;
height: 50px;
width: 200px;
background-color: red;
top: 50%;
transform: translateY(-50%);
margin: auto;
}
#loader .center div {
width: 2px;
height: 50px;
background-color: blue;
float: left;
padding: 0px;
margin-right: 5px;
margin-bottom: 25px;
position: relative;
}
<body onload="loading()">
<div id="loader">
<div class="center" id="loader-ul">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</body>
Upvotes: 1