现代异步原语
您拥有的当前功能没有任何“错误”,但我认为它可以得到显着改进。 JavaScript 提供了一个现代化的异步原子 Promise 和新的语法支持 async/await。这些比石器时代的 setTimeout 和 setInterval 更受欢迎,因为您可以轻松地将数据线程化通过异步控制流,停止考虑“回调”,并避免副作用 -
class Algorithm {
constructor() {
...
this.runProcess(...)
}
async runProcess(...) { // async
while (true) { // loop instead of recursion
await sleep(...) // sleep some amount of time
this.someFunction() // do work
... // adjust timer variables
}
}
}
sleep 是一个简单的函数,它在指定的毫秒值 ms 之后解析一个承诺 -
function sleep(ms) {
return new Promise(r => setTimeout(r, ms)) // promise
}
异步迭代
但是看看this.someFunction() 怎么没有返回任何东西?如果我们能从someFunction 捕获数据并将其提供给我们的调用者,那就太好了。通过将runProcess 设为async generator 并实现Symbol.asyncIterator,我们可以轻松处理异步和停止副作用-
class Algorithm {
constructor() {
...
this.data = this.runProcess(...) // assign this.data
}
async *runProcess(...) { // async generator
while (true) {
await sleep(...)
yield this.someFunction() // yield
...
}
}
[Symbol.asyncIterator]() { // iterator
return this.data
}
}
现在调用者可以控制从this.someFunction 传入数据时发生的情况。下面我们写信给console.log,但您可以轻松地将其替换为 API 调用或写入文件系统 -
const foo = new Algorithm(...)
for await (const data of foo)
console.log("process data", data) // or API call, or write to file system, etc
附加控制
您可以通过使用其他数据成员轻松添加对流程的控制。下面我们用条件替换while(true),并允许调用者停止进程-
class Algorithm {
constructor() {
...
}
async *runProcess(...) {
this.running = true // start
while (this.running) { // conditional loop
...
}
}
haltProcess() {
this.running = false // stop
}
...
}
演示
这是一个包含上述概念的功能演示。注意我们在这里只实现halt 因为run 是一个infinite 生成器。有限生成器不需要手动停止。通过运行 sn -p 在您自己的浏览器中验证结果 -
class Algorithm {
async *run() {
this.running = true
while(this.running) {
await sleep(1000)
yield this.someFunction()
}
}
halt() {
this.running = false
}
someFunction() {
return Math.random()
}
[Symbol.asyncIterator] = this.run
}
function sleep(ms) {
return new Promise(r => setTimeout(r, ms))
}
async function main() {
const foo = new Algorithm // init
setTimeout(_ => foo.halt(), 10000) // stop at some point, for demo
for await (const x of foo) // iterate
console.log("data", x) // log, api call, write fs, etc
return "done" // return something when done
}
main().then(console.log, console.error) // "done"
data 0.3953947360028206
data 0.18754462176783115
data 0.23690422070864803
data 0.11237466374294014
data 0.5123244720637253
data 0.39818889343799635
data 0.08627407687877853
data 0.3861902404922477
data 0.8358471443658225
data 0.2770336562516085
done