Comment «multidiffuser» un itérable asynchrone?
Un asyncgénérateur peut-il être en quelque sorte diffusé ou multicast, de sorte que tous ses itérateurs («consommateurs»? Abonnés?) Reçoivent toutes les valeurs?
Prenons cet exemple:
const fetchMock = () => "Example. Imagine real fetch";
async function* gen() {
for (let i = 1; i <= 6; i++) {
const res = await fetchMock();
yield res.slice(0, 2) + i;
}
}
const ait = gen();
(async() => {
// first "consumer"
for await (const e of ait) console.log('e', e);
})();
(async() => {
// second...
for await (const é of ait) console.log('é', é);
})();
Les itérations "consomment" une valeur, donc seule l'une ou l'autre l'obtient. Je voudrais que les deux (et les plus récents) obtiennent chaque yieldvaleur ed, si un tel générateur est possible de créer d'une manière ou d'une autre. (Similaire à un Observable.)
Réponses
Ce n'est pas facilement possible. Vous devrez le mettre explicitement en tee . Ceci est similaire à la situation pour les itérateurs synchrones , juste un peu plus compliqué:
const AsyncIteratorProto = Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}.prototype));
function teeAsync(iterable) {
const iterator = iterable[Symbol.asyncIterator]();
const buffers = [[], []];
function makeIterator(buffer, i) {
return Object.assign(Object.create(AsyncIteratorProto), {
next() {
if (!buffer) return Promise.resolve({done: true, value: undefined});
if (buffer.length) return buffer.shift();
const res = iterator.next();
if (buffers[i^1]) buffers[i^1].push(res);
return res;
},
async return() {
if (buffer) {
buffer = buffers[i] = null;
if (!buffers[i^1]) await iterator.return();
}
return {done: true, value: undefined};
},
});
}
return buffers.map(makeIterator);
}
Vous devez vous assurer que les deux itérateurs sont consommés à peu près au même rythme afin que la mémoire tampon ne devienne pas trop grande.
Tu veux dire ça?
async function* gen() {
for (let i = 1; i <= 6; i++) yield i;
}
//const ait = gen();
(async() => {
// first iteration
const ait = gen()
for await (const e of ait) console.log(1, e);
})();
(async() => {
// second...
const ait = gen()
for await (const é of ait) console.log(2, é);
})();