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

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

问题描述

我正在开发一个 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.

所有 promise 都使用 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 将创建一个在 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

// stop after 5 seconds
setTimeout (() => RUNNING = false, 5000)

这是一个工作演示

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天全站免登陆