运行多个递归承诺,并在需要时中断 [英] Run multiple recursive Promises and break when requested

查看:57
本文介绍了运行多个递归承诺,并在需要时中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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

我们对ColorstepColorsetElemColor(以及其他)做了一些如意算盘的想法,让我们首先实现这些

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

最后,我们编写辅助程序delayeffect. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆