如何使用 Promise 链接 CSS 动画?
How to chain CSS animations using Promise?
我正在尝试弄清楚 Promise
是如何工作的,并制作一个 CSS 动画到 运行 接一个。但是他们 运行 同时...
let move_boxes = () => {
return new Promise( (resolve, reject) => {
resolve ('boxes moved!')
})
};
let move_box_one = () => {
return new Promise( (resolve, reject) => {
resolve (document.getElementById('div_two').style.animation = 'move 3s forwards')
console.log('box one moved!')
})
}
let move_box_two = () => {
return new Promise( (resolve, reject) => {
resolve (document.getElementById('div_one').style.animation = 'move 3s forwards')
console.log('box two moved!')
})
}
move_boxes().then(() => {
return move_box_one();
}).then(() => {
return move_box_two();
});
您需要等待动画完成,这是一个工作代码,
let move_boxes = () => {
return new Promise( (resolve, reject) => {
resolve ('boxes moved!')
})
};
let move_box_one = () => {
return new Promise( (resolve, reject) => {
document.getElementById('div_two').style.animation = 'move 3s forwards';
setTimeout(()=> resolve(), 3000);
})
}
let move_box_two = () => {
return new Promise( (resolve, reject) => {
document.getElementById('div_one').style.animation = 'move 3s forwards';
setTimeout(()=> resolve(), 3000);
})
}
move_boxes().then(() => {
return move_box_one();
}).then(() => {
return move_box_two();
});
工作fiddle:https://jsfiddle.net/bu96cxak/
与发布的答案相反,我不鼓励使用 window.setTimeout
,因为它不能保证计时器与动画结束事件同步,有时这些事件会卸载到 GPU。如果您想更加确定,您应该收听 animationend
event,并在回调本身中解决它,即:
let move_box_one = () => {
return new Promise((resolve, reject) => {
const el = document.getElementById('div_one');
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = 'move 3s forwards';
});
}
更好的是,由于您为两个框编写了一些重复的逻辑,您可以将所有这些抽象为一个通用函数,returns 一个承诺:
// We can declare a generic helper method for one-time animationend listening
let onceAnimationEnd = (el, animation) => {
return new Promise(resolve => {
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = animation;
});
}
let move_box_one = async () => {
const el = document.getElementById('div_one');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_box_two = async () => {
const el = document.getElementById('div_two');
await onceAnimationEnd(el, 'move 3s forwards');
}
此外,您的 move_boxes
函数有点复杂。如果你想 运行 异步移动单个框的动画,将其声明为异步方法并简单地等待单个框移动函数调用,即:
let move_boxes = async () => {
await move_box_one();
await move_box_two();
}
move_boxes().then(() => console.log('boxes moved'));
查看概念验证示例(或者您可以从原始示例的 this JSFiddle that I've forked 中查看):
// We can declare a generic helper method for one-time animationend listening
let onceAnimationEnd = (el, animation) => {
return new Promise(resolve => {
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = animation;
});
}
let move_box_one = async () => {
const el = document.getElementById('div_one');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_box_two = async () => {
const el = document.getElementById('div_two');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_boxes = async () => {
await move_box_one();
await move_box_two();
}
move_boxes().then(() => console.log('boxes moved'));
#div_one {
width: 50px;
height: 50px;
border: 10px solid red;
}
#div_two {
width: 50px;
height: 50px;
border: 10px solid blue;
}
@keyframes move {
100% {
transform: translateX(300px);
}
}
@keyframes down {
100% {
transform: translateY(300px);
}
}
<div id="div_one"></div>
<div id="div_two"></div>
当您知道相应的动画事件已完成时,您将只想解决承诺。
您可以为此使用 animationend
事件,这比使用具有预期持续时间的 setTimeout
更合适。
创建一个用于为其创建承诺的实用函数,然后将其重新用于任何元素和任何动画描述也将很有用:
const promiseAnimation = (elem, animation) => new Promise(resolve => {
elem.style.animation = animation;
elem.addEventListener("animationend", resolve);
});
const $ = document.querySelector.bind(document);
const moveBoxOne = () => promiseAnimation($("#div_one"), "move 3s forwards");
const moveBoxTwo = () => promiseAnimation($("#div_two"), "move 3s forwards");
Promise.resolve()
.then(moveBoxOne)
.then(() => console.log("one has moved"))
.then(moveBoxTwo)
.then(() => console.log("two has moved"))
div { display: inline-block; position: relative; border: 1px solid; }
@keyframes move {
from {margin-left: 0px;}
to {margin-left: 100px;}
}
<div id="div_one">div_one</div><br>
<div id="div_two">div_two</div>
Promise 并不意味着它将是异步的。由于解决是即时的,因此他们很可能同时 运行。如果你想延迟,你可以使用 setTimeout 在调用中创建延迟。
const delay = (dl) => new Promise(r => {
setTimeout(r, dl)
})
let move_box_one = () => {
document.getElementById('div_two').style.animation = 'move 3s forwards'
console.log('box one moved!')
}
let move_box_two = () => {
document.getElementById('div_one').style.animation = 'move 3s forwards'
console.log('box two moved!')
}
(async function() {
move_box_one()
await delay(200)
move_box_two()
})()
我正在尝试弄清楚 Promise
是如何工作的,并制作一个 CSS 动画到 运行 接一个。但是他们 运行 同时...
let move_boxes = () => {
return new Promise( (resolve, reject) => {
resolve ('boxes moved!')
})
};
let move_box_one = () => {
return new Promise( (resolve, reject) => {
resolve (document.getElementById('div_two').style.animation = 'move 3s forwards')
console.log('box one moved!')
})
}
let move_box_two = () => {
return new Promise( (resolve, reject) => {
resolve (document.getElementById('div_one').style.animation = 'move 3s forwards')
console.log('box two moved!')
})
}
move_boxes().then(() => {
return move_box_one();
}).then(() => {
return move_box_two();
});
您需要等待动画完成,这是一个工作代码,
let move_boxes = () => {
return new Promise( (resolve, reject) => {
resolve ('boxes moved!')
})
};
let move_box_one = () => {
return new Promise( (resolve, reject) => {
document.getElementById('div_two').style.animation = 'move 3s forwards';
setTimeout(()=> resolve(), 3000);
})
}
let move_box_two = () => {
return new Promise( (resolve, reject) => {
document.getElementById('div_one').style.animation = 'move 3s forwards';
setTimeout(()=> resolve(), 3000);
})
}
move_boxes().then(() => {
return move_box_one();
}).then(() => {
return move_box_two();
});
工作fiddle:https://jsfiddle.net/bu96cxak/
与发布的答案相反,我不鼓励使用 window.setTimeout
,因为它不能保证计时器与动画结束事件同步,有时这些事件会卸载到 GPU。如果您想更加确定,您应该收听 animationend
event,并在回调本身中解决它,即:
let move_box_one = () => {
return new Promise((resolve, reject) => {
const el = document.getElementById('div_one');
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = 'move 3s forwards';
});
}
更好的是,由于您为两个框编写了一些重复的逻辑,您可以将所有这些抽象为一个通用函数,returns 一个承诺:
// We can declare a generic helper method for one-time animationend listening
let onceAnimationEnd = (el, animation) => {
return new Promise(resolve => {
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = animation;
});
}
let move_box_one = async () => {
const el = document.getElementById('div_one');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_box_two = async () => {
const el = document.getElementById('div_two');
await onceAnimationEnd(el, 'move 3s forwards');
}
此外,您的 move_boxes
函数有点复杂。如果你想 运行 异步移动单个框的动画,将其声明为异步方法并简单地等待单个框移动函数调用,即:
let move_boxes = async () => {
await move_box_one();
await move_box_two();
}
move_boxes().then(() => console.log('boxes moved'));
查看概念验证示例(或者您可以从原始示例的 this JSFiddle that I've forked 中查看):
// We can declare a generic helper method for one-time animationend listening
let onceAnimationEnd = (el, animation) => {
return new Promise(resolve => {
const onAnimationEndCb = () => {
el.removeEventListener('animationend', onAnimationEndCb);
resolve();
}
el.addEventListener('animationend', onAnimationEndCb)
el.style.animation = animation;
});
}
let move_box_one = async () => {
const el = document.getElementById('div_one');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_box_two = async () => {
const el = document.getElementById('div_two');
await onceAnimationEnd(el, 'move 3s forwards');
}
let move_boxes = async () => {
await move_box_one();
await move_box_two();
}
move_boxes().then(() => console.log('boxes moved'));
#div_one {
width: 50px;
height: 50px;
border: 10px solid red;
}
#div_two {
width: 50px;
height: 50px;
border: 10px solid blue;
}
@keyframes move {
100% {
transform: translateX(300px);
}
}
@keyframes down {
100% {
transform: translateY(300px);
}
}
<div id="div_one"></div>
<div id="div_two"></div>
当您知道相应的动画事件已完成时,您将只想解决承诺。
您可以为此使用 animationend
事件,这比使用具有预期持续时间的 setTimeout
更合适。
创建一个用于为其创建承诺的实用函数,然后将其重新用于任何元素和任何动画描述也将很有用:
const promiseAnimation = (elem, animation) => new Promise(resolve => {
elem.style.animation = animation;
elem.addEventListener("animationend", resolve);
});
const $ = document.querySelector.bind(document);
const moveBoxOne = () => promiseAnimation($("#div_one"), "move 3s forwards");
const moveBoxTwo = () => promiseAnimation($("#div_two"), "move 3s forwards");
Promise.resolve()
.then(moveBoxOne)
.then(() => console.log("one has moved"))
.then(moveBoxTwo)
.then(() => console.log("two has moved"))
div { display: inline-block; position: relative; border: 1px solid; }
@keyframes move {
from {margin-left: 0px;}
to {margin-left: 100px;}
}
<div id="div_one">div_one</div><br>
<div id="div_two">div_two</div>
Promise 并不意味着它将是异步的。由于解决是即时的,因此他们很可能同时 运行。如果你想延迟,你可以使用 setTimeout 在调用中创建延迟。
const delay = (dl) => new Promise(r => {
setTimeout(r, dl)
})
let move_box_one = () => {
document.getElementById('div_two').style.animation = 'move 3s forwards'
console.log('box one moved!')
}
let move_box_two = () => {
document.getElementById('div_one').style.animation = 'move 3s forwards'
console.log('box two moved!')
}
(async function() {
move_box_one()
await delay(200)
move_box_two()
})()