与 js 生成器进行 2 路通信的能力非常强大(参见 here )。它支持类似于基于 CSP 的编程语言中的 channel 的功能。
不过,我似乎不知道如何使用异步生成器来做到这一点。假设我通过以下方式创建一个异步生成器:
async function* asyncGenFn() {
yield Promise.resolve(true)
}
该函数返回AsyncIterableIterator
(不是 AsyncIterator
),它似乎没有 next
功能类似于 IterablIterator
确实如此。
有没有办法与以这种方式创建的异步生成器进行双向通信?或者我只是在这里咆哮错误的树?
最佳答案
这是使用生成器进行双向通信的示例 -
const g = function* (x)
{ // yield sends a message "out"
// inbound message will be assigned to msg1
const msg1 = yield "sending this out"
// another outbound message
// inbound message will be assigned to msg2
const msg2 = yield "sending this too"
// do something
console.log(msg1, msg2)
// finally, return a value
// don't forget generators can accept arguments, like x here
return x * 2
}
// instantiate the generator
const iterator = g (100)
// get the first value from the iterator
let val = iterator.next()
// some example message to send to the generator
let m = 1
while (!val.done)
{ // log each outbound message
console.log("received message", val.value)
// .next resumes the generator and sends a message back "in"
val = iterator.next(m)
// increment the example message
m = m + 1
}
// display the final value
console.log("return value", val.value)
输出
received message sending this out
received message sending this too
1 2
return value 200
<小时/>
通过将其应用于问题来了解双向通信可能会更好。生成器为我们提供的这种暂停/恢复行为使它们非常适合处理异步操作。较新的 async
和 await
使我们能够模糊同步和异步代码之间的界限 -
const delay = x =>
new Promise (r => setTimeout (r, 1e3, x))
const main = async (z) =>
{ const x = await delay (200) // some promise
const y = await delay (300) // some promise
return x + y + z // some computation with all the values
}
main (100) .then (console.log, console.error)
// 2 seconds later...
// => 600
但在我们拥有 async
和 await
之前,我们有生成器。下面的 run
是与生成器进行双向通信的一个很好的演示。它允许我们以完全相同的方式编写程序,除了使用生成器函数和 yield
表达式 -
const delay = x =>
new Promise (r => setTimeout (r, 1e3, x))
const main = function* (z)
{ const x = yield delay (200) // some promise
const y = yield delay (300) // some promise
return x + y + z // some computation with all the values
}
const run = it =>
{ const loop = ({ done, value }) =>
done
? Promise .resolve (value)
: value .then (x => loop (it .next (x)))
return loop (it .next ())
}
run (main (100)) .then (console.log, console.error)
// 2 seconds later...
// => 600
上面,run
被实现为一个简单的递归函数,它接受生成器的出站 promise 并将 promise 的解析值发送回生成器。它会执行此操作,直到生成器耗尽并解析出最终值 -
const run = it =>
{ const loop = ({ done, value }) =>
// if the iterator is done
done
// resolve the final value
? Promise .resolve (value)
// otherwise resolve the value, send it back into the generator, recur
: value .then (x => loop (it .next (x)))
// initialize the loop with the first value
return loop (it .next ())
}
在我们可以使用生成器来模拟协程之前,我们一直在通过手动链接代码中的 .then
调用来编写异步程序 -
const delay = x =>
new Promise (r => setTimeout (r, 1e3, x))
const main = z =>
delay (200) .then (x => // manually chain then
delay (300) .then (y => // manually chain then
x + y + z // some computation with all the values
)) // close each then
main (100) .then (console.log, console.error)
// 2 seconds later...
// => 600
正如您所看到的,与生成器的双向通信非常强大,为我们提供了复杂程序的精美表达。 JavaScript 添加了 async
/await
关键字,这可能看起来很神奇,但 run
让您了解如何使用双向通信即使没有新关键字,也能获得相同的行为。
关于javascript - 如何与异步 JavaScript 生成器进行双向通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54224476/