如何通过MessageChannel传递异步生成器?重构remoteGenerator为异步生成器
重构 RemoteGenerator 为异步生成器
以下是实现跨上下文生成器交互的原始代码:
function remoteGenerator(port) { const createPromise = () => { let handlers; return { promise: new Promise( (resolve, reject) => (handlers = { resolve, reject }) ), get handlers() { return handlers; }, }; }; const createIterator = (run) => { const iterator = { next: run, return: (arg) => run(arg, 'return'), [Symbol.asyncIterator]: () => iterator, }; return iterator; }; let done = false; let { promise, handlers } = createPromise(); const step = createIterator((arg, name = 'next') => { const original = promise; if (done) return original; port.postMessage({ name, arg }); promise = promise.then(() => { if (done) return original; const next = createPromise(); handlers = next.handlers; return next.promise; }); return original; }); port.onmessage = (evt) => { done = evt.data.done; handlers[evt.data.handler]({ done: evt.data.done, value: evt.data.value }); }; return step; } // usage async function* startCounterAsync(delay = 1000) { let i = 0; while (i < 10) { yield i++; await new Promise((r) => setTimeout(r, delay)); } } const startRemoteGenerator = result => { const mc = new MessageChannel() mc.port1.onmessage = async (evt) => { let nextResult; try { nextResult = await result[evt.data.name](evt.data.arg); mc.port1.postMessage({ name: nextResult.done ? 'return' : 'next', handler: 'resolve', value: nextResult.value, done: nextResult.done, }); } catch (err) { mc.port1.postMessage({ name: 'return', handler: 'reject', value: err, done: true, }); } nextResult.done && port.close(); }; return remoteGenerator(mc.port2); } for await (let value of startRemoteGenerator(startCounterAsync())) { console.log(value); }
remoteGenerator 函数接收 MessageChannel 的一个端口,与消息通道另一端的生成器或异步生成器交互,为不同上下文的执行提供透明接口。
现在希望将 remoteGenerator 重构为异步生成器本身,但存在核心障碍:无法提前知晓远端生成器会返回值还是产出值。为了向远端生成器传递参数,需要在本地执行 yield,而该操作应返回远端生成器产出的值,但似乎无法取消或替换正在进行的 yield 为 return(设置 { done: true })。
目前找到的解决方案是使用包装函数:
async function* remoteGeneratorWrapper(port) { const it = remoteGenerator(port); yield* it; return (await it.return()).value; }
但希望简化方案,去掉中间异步迭代器。
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

