运行多个递归承诺,并在需要时中断 [英] Run multiple recursive Promises and break when requested
问题描述
我正在使用LED灯带动画工具,该工具允许用户选择可以同时运行的多个效果.每个效果都是一个(蓝鸟)承诺.有一个run()
方法可以设置LED灯带的颜色.
I'm working on a LED strip animation tool which allows the user to select multiple effects which can run simultaneously. Each effect is a (bluebird) Promise. There is a single run()
method which sets the color of the LED strip.
所有诺言都使用delay
方法以固定的FPS运行.
All promises run at a fixed FPS using the delay
method.
run(mode) {
return this.setStripColor(this.color).delay(1 / this.fps).then(() => { this.run(1 / this.fps) })
}
// example of an effect
rainbowSweep() {
// ..
// magical unicorn code
// ..
return Promise.resolve().delay(1 / this.fps).then(() => {
this.rainbowSweep()
})
app.rainbowSweep()
app.run()
是否可以使用某种数据结构来启用和禁用递归承诺?换句话说,我如何发出信号(递归承诺)停止递归?
Is there some sort of data structure that I can use where I can toggle on and off a recursive promise? In other words, how do I signal to the effect (the recursive promise) to stop recursing?
我正在考虑一个包含所有承诺的数组.
但是,当数组中不再存在递归诺言时,我不知道如何打破/解决它. return
在promise本身是否在数组内之前,我可以进行检查,但是我希望有一种更优雅的方法.
I was thinking of an array containing all the promises.
But then I don't know how to break/resolve a recursive promise when it's no longer in the array. I could do a check before I return
whether the promise itself is inside the array, but I was hoping there was a more elegant way.
推荐答案
让我们看一个简单的递归函数,该递归函数可以高层表达我们的程序
Let's look at a simple recursive function that expresses our program at a high level
let RUNNING =
true
const main = async (elem, color = Color ()) =>
RUNNING
? delay (color, FPS)
.then (effect (color => setElemColor (elem, color)))
.then (color => main (elem, stepColor (color)))
: color
我们对Color
,stepColor
和setElemColor
(以及其他)做了一些如意算盘的想法,让我们首先实现这些
We've done a little wishful thinking with Color
, stepColor
, and setElemColor
(among others), let's implement those first
const Color = (r = 128, g = 128, b = 128) =>
({ r, g, b })
const stepColor = ({ r, g, b }, step = 8) =>
b < 255
? Color (r, g, b + step)
: g < 255
? Color (r, g + step, 0)
: r < 255
? Color (r + step, 0, 0)
: Color (0, 0, 0)
const setElemColor = (elem, { r, g, b }) =>
elem.style.backgroundColor = `rgb(${r}, ${g}, ${b})`
const c = new Color () // { r: 128, g: 128, b: 128 }
setpColor (c) // { r: 128, g: 128, b: 136 }
现在,我们有了一种创建颜色,获取下一个"颜色的方法,并且可以设置HTML元素的颜色
Now we have a way to create colors, get the "next" color, and we can set the color of an HTML element
最后,我们编写辅助程序delay
和effect
. delay
将创建一个Promised值,该值在ms
毫秒内解析. effect
用于具有副作用的功能(例如设置HTML元素的属性).而FPS
只是我们的每秒帧数
Lastly, we write helpers delay
and effect
. delay
will create a Promised value that resolves in ms
milliseconds. effect
is used for functions which have a side effect (like setting the property of an HTML element). and FPS
is just our frames-per-second constant
const delay = (x, ms) =>
new Promise (r => setTimeout (r, ms, x))
const effect = f => x =>
(f (x), x)
const FPS =
1000 / 30
要运行该程序,只需使用输入元素调用main
.因为它是一个异步程序,所以请不要忘记处理成功的和错误案例.当程序最终停止时,将输出最后使用的颜色.
To run the program, just call main
with an input element. Because it's an asynchronous program, don't forget to handle both the success and errors cases. When the program finally stops, the last used color will be output.
main (document.querySelector('#main'))
.then (console.log, console.error)
// => { Color r: 136, g: 8, b: 40 }
要停止该程序,只需随时设置RUNNING = false
To stop the program, just set RUNNING = false
at any time
// stop after 5 seconds
setTimeout (() => RUNNING = false, 5000)
这是一个正在运行的演示
Here's a working demo
const Color = (r = 128, g = 128, b = 128) =>
({ r, g, b })
const stepColor = ({ r, g, b }, step = 16) =>
b < 255
? Color (r, g, b + step)
: g < 255
? Color (r, g + step, 0)
: r < 255
? Color (r + step, 0, 0)
: Color (0, 0, 0)
const setElemColor = (elem, { r, g, b }) =>
elem.style.backgroundColor = `rgba(${r}, ${g}, ${b}, 1)`
const delay = (x, ms) =>
new Promise (r => setTimeout (r, ms, x))
const effect = f => x =>
(f (x), x)
const FPS =
1000 / 60
let RUNNING =
true
const main = async (elem, color = Color ()) =>
RUNNING
? delay (color, FPS)
.then (effect (color => setElemColor (elem, color)))
.then (color => main (elem, stepColor (color)))
: color
main (document.querySelector('#main'))
.then (console.log, console.error)
// => { r: 136, g: 8, b: 40 }
// stop after 5 seconds
setTimeout (() => RUNNING = false, 5000)
#main {
width: 100px;
height: 100px;
background-color: rgb(128, 128, 128);
}
<div id="main"></div>
<p>runs for 5 seconds...</p>
这篇关于运行多个递归承诺,并在需要时中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!