让我们看一个简单的递归函数,它在高层次上表达了我们的程序
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 元素的颜色
最后,我们编写助手delay 和effect。 delay 将创建一个在 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>