在这里创建一个承诺,在那里解决它
Create a promise here, resolve it there
我以为我在所有情况下都有承诺的窍门,但我被困在这里:我希望动画在计时器上发生。我唯一能从图形包中得到的是帧数,所以我根据帧速率估计计算结束帧。
图形包是 p5.js,它公开了 frameCount
,在每个绘制周期中仅以大约 60 fps 的速度运行。 (我在这个问题中将其命名为 currentFrame,希望能澄清)。据我所知,这是我在 p5.js
中进入动画帧状态的唯一可见性
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
// animation done
}
}
让我感到困惑的是如何给 doAnimation 调用者一个在其他方法中解决的承诺。我试过这个:
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
this.animationPromise = new Promise(resolve => {
// I realize this is wrong, but it illustrates the problem. How do I run this test later?
if (currentFrame >= this.endFrame) resolve();
});
return this.animationPromise;
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
this.animationPromise.resolve(); // also wrong, I think
// since resolve isn't an instance method of a promise
}
}
有人能帮我澄清一下吗?
您需要存储解析器以调用:
而不是存储要解析的承诺
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
return new Promise(resolve => {
this.onAnimationFinished = resolve;
});
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
this.onAnimationFinished();
}
}
当然你需要确保一次只调用一次doAnimation()
,并且draw()
不会在doAnimation()
之前被调用(或者更准确地说,onAnimationFinished
在设置 endFrame
时设置)。一旦到达结束帧,您可能还想将它们重置(undefined
)。
一般来说,履行或拒绝承诺应该由在您传递的执行程序函数中启动的进程完成 new Promise
。很少需要从外部履行或拒绝承诺(至少,调用者意识到这是承诺履行的方式)。
我会使用回调队列:
维护一个待定动画列表,其中包含它们结束的帧和回调。
让 draw
在队列中查找它应该根据(新)currentFrame
.
调用的动画回调
让doAnimation
代码排队回调
大致:
activeAnimations = [];
doAnimation(duration) {
// animation stuff
const endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
return new Promise(resolve => {
this.activeAnimations.push({
endFrame,
done: resolve, // Or possibly: `done: () => resolve()`
// so this code is in control of whether
// there's a fulfillment value
});
});
}
draw() {
for (let index = 0; index < this.activeAnimations; ++index) {
const animation = this.activeAnimations[index];
if (currentFrame > animation.endFrame) {
// Animation done
animation.done();
this.activeAnimations.splice(index, 1);
--index;
} else {
// Continue animation
}
}
}
done: () => resolve()
评论的原因是,一般来说,我尽量避免直接将 promise resolve
/reject
函数暴露给 promise 执行程序之外的代码,根据它之外的代码通常不应该直接控制承诺发生的事情。 (我为 setTimeout
破例。:-))但这可能有点过分了。
作为替代方案,您还可以在 promise 构造函数回调中分配给 draw
:
function basicDraw() {
// ...
}
var draw = basicDraw; // Default function
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
return new Promise((resolve) => {
draw = () => {
basicDraw();
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
draw = basicDraw; // back to normal
resolve();
}
};
});
}
doAnimation(1000).then(() => {
/* whatever you want to do next */
});
我以为我在所有情况下都有承诺的窍门,但我被困在这里:我希望动画在计时器上发生。我唯一能从图形包中得到的是帧数,所以我根据帧速率估计计算结束帧。
图形包是 p5.js,它公开了 frameCount
,在每个绘制周期中仅以大约 60 fps 的速度运行。 (我在这个问题中将其命名为 currentFrame,希望能澄清)。据我所知,这是我在 p5.js
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
// animation done
}
}
让我感到困惑的是如何给 doAnimation 调用者一个在其他方法中解决的承诺。我试过这个:
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
this.animationPromise = new Promise(resolve => {
// I realize this is wrong, but it illustrates the problem. How do I run this test later?
if (currentFrame >= this.endFrame) resolve();
});
return this.animationPromise;
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
this.animationPromise.resolve(); // also wrong, I think
// since resolve isn't an instance method of a promise
}
}
有人能帮我澄清一下吗?
您需要存储解析器以调用:
而不是存储要解析的承诺doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
return new Promise(resolve => {
this.onAnimationFinished = resolve;
});
}
draw() {
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
this.onAnimationFinished();
}
}
当然你需要确保一次只调用一次doAnimation()
,并且draw()
不会在doAnimation()
之前被调用(或者更准确地说,onAnimationFinished
在设置 endFrame
时设置)。一旦到达结束帧,您可能还想将它们重置(undefined
)。
一般来说,履行或拒绝承诺应该由在您传递的执行程序函数中启动的进程完成 new Promise
。很少需要从外部履行或拒绝承诺(至少,调用者意识到这是承诺履行的方式)。
我会使用回调队列:
维护一个待定动画列表,其中包含它们结束的帧和回调。
让
调用的动画回调draw
在队列中查找它应该根据(新)currentFrame
.让
doAnimation
代码排队回调
大致:
activeAnimations = [];
doAnimation(duration) {
// animation stuff
const endFrame = currentFrame + (60 * duration); // 60fps seems to be a good guess
return new Promise(resolve => {
this.activeAnimations.push({
endFrame,
done: resolve, // Or possibly: `done: () => resolve()`
// so this code is in control of whether
// there's a fulfillment value
});
});
}
draw() {
for (let index = 0; index < this.activeAnimations; ++index) {
const animation = this.activeAnimations[index];
if (currentFrame > animation.endFrame) {
// Animation done
animation.done();
this.activeAnimations.splice(index, 1);
--index;
} else {
// Continue animation
}
}
}
done: () => resolve()
评论的原因是,一般来说,我尽量避免直接将 promise resolve
/reject
函数暴露给 promise 执行程序之外的代码,根据它之外的代码通常不应该直接控制承诺发生的事情。 (我为 setTimeout
破例。:-))但这可能有点过分了。
作为替代方案,您还可以在 promise 构造函数回调中分配给 draw
:
function basicDraw() {
// ...
}
var draw = basicDraw; // Default function
doAnimation(duration) {
// animation stuff
this.endFrame = currentFrame + (60 * duration);
return new Promise((resolve) => {
draw = () => {
basicDraw();
if (currentFrame < this.endFrame) {
// compute and draw the state of the animation
} else if (currentFrame >= this.endFrame) {
draw = basicDraw; // back to normal
resolve();
}
};
});
}
doAnimation(1000).then(() => {
/* whatever you want to do next */
});