javascript - 运行多个递归 Promise 并在请求时中断

标签 javascript recursion bluebird

我正在开发一个 LED 条动画工具,它允许用户选择可以同时运行的多种效果。每个效果都是一个( Bluebird ) promise 。有一个 run() 方法可以设置 LED 灯带的颜色。

所有 Promise 使用 delay 方法以固定的 FPS 运行。

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()

是否可以使用某种数据结构来打开和关闭递归 promise ?换句话说,我如何向效果(递归 promise )发出停止递归的信号?

我正在考虑一个包含所有 promise 的数组。 但是当递归 promise 不再存在于数组中时,我不知道如何打破/解决它。我可以在返回之前检查一下 promise 本身是否在数组内,但我希望有一种更优雅的方法。

最佳答案

让我们看一个简单的递归函数,它在较高层次上表达我们的程序

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 (除其他外),让我们首先实现这些

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 元素的颜色

最后,我们编写助手 delayeffectdelay将创建一个解析为 ms 的 Promised 值毫秒。 effect用于具有副作用的函数(例如设置 HTML 元素的属性)。和FPS只是我们的每秒帧数常数

const delay = (x, ms) =>
  new Promise (r => setTimeout (r, ms, x))

const effect = f => x =>
  (f (x), x)

const FPS =
  1000 / 30

要运行该程序,只需调用 main带有输入元素。因为它是一个异步程序,所以不要忘记处理成功和错误情况。当程序最终停止时,将输出最后使用的颜色。

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>

关于javascript - 运行多个递归 Promise 并在请求时中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48349721/

相关文章:

javascript - Jquery信息图

javascript - 在knockout.js中使用$parentContext.$index访问父循环ID

C++:递归追加链表

java - 如何使用反射递归序列化对象?

Bluebird Promise join 未按顺序运行

javascript - 函数适用于 Promises

javascript - 使用 Bluebird.js 和 Twitter 流的 promise 和流

javascript - IE 和 Firefox 之间空 XML 响应的不同行为

python - 递归地将pymysql Comment对象转换为树

javascript - 在网络浏览器中实现一个好的 redis 客户端需要什么?