raaymaxR
Deno2y ago
3 replies
raaymax

Event loop resolving prematurely

It looks like event loop clears on await it.return?.(); call which is really strange. I can't figure out whats happening here and where the problem is.
Can anyone help with that?

import { assert } from 'jsr:@std/assert@^1.0.0';

async function* abortable(
  p: ReadableStream<Uint8Array>,
  signal: AbortSignal,
): AsyncGenerator<Uint8Array> {
  signal.throwIfAborted();
  const { promise, reject } = Promise.withResolvers<never>();
  const abort = () => reject(signal.reason);
  signal.addEventListener("abort", abort, { once: true });

  const it = p[Symbol.asyncIterator]();
  try{
    while (true) {
      const race = Promise.race([promise, it.next()]);
      race.catch(() => {
        signal.removeEventListener("abort", abort);
      });
      const { done, value } = await race;
      if (done) {
        signal.removeEventListener("abort", abort);
        return;
      }
      yield value;
    }
  }catch(e){
    await it.return?.();
    throw e;
  }
}

Deno.test('aborting streams', async () => {
  let streamClosed = false;
  const stream = new ReadableStream<Uint8Array>({
    cancel() {
      streamClosed = true;
      console.log('Stream closed');
    }
  });
  console.log('stream created');
  const signalController = new AbortController();
  setTimeout(() => signalController.abort(), 1000);
  try{
    for await (const _ of abortable(stream, signalController.signal)) {
      console.log('Got data');
    }
  }catch(e){
    console.error(e);
  }
  console.log('Stream closed');
  assert(streamClosed);
});

Execution result
❯ deno test -A strange.test.ts
running 1 test from ./oko.test.ts
aborting streams ...
------- output -------
stream created
----- output end -----

ok | 0 passed | 0 failed (1s)

error: Promise resolution is still pending but the event loop has already resolved.
Was this page helpful?