Skip to content
English

事件流单槽交接与背压 ​

策略的具体实现如下。

ts
export async function* streamEvents<Event>(
  operation: (emit: (event: Event) => Promise<void>) => Promise<void>,
  { signal }: import('../structs/common.js').ExecutionContext,
): AsyncIterable<Event> {
  let slot: { event: Event; release(): void; cancel(): void } | undefined;
  let wake: (() => void) | undefined;
  let closed = false,
    done = false;
  let sending = false;
  let failure: { error: unknown } | undefined;
  let rejectSend: ((error: unknown) => void) | undefined;
  const notify = () => {
    wake?.();
    wake = undefined;
  };
  const abort = () => {
    closed = true;
    rejectSend?.(signal.reason ?? new Error('Stream closed'));
    notify();
  };
  signal.addEventListener('abort', abort, { once: true });
  if (signal.aborted) abort();
  const producer = Promise.resolve()
    .then(() => {
      signal.throwIfAborted();
      // Before the producer starts, only abort can close this rendezvous; the
      // signal check above already rejects it with the original reason.
      return operation((event) => {
        if (closed || signal.aborted)
          return Promise.reject(signal.reason ?? new Error('Stream closed'));
        if (sending) return Promise.reject(new Error('Event producers must await delivery'));
        sending = true;
        return new Promise<void>((resolve, reject) => {
          rejectSend = reject;
          slot = {
            event,
            release: () => {
              sending = false;
              resolve();
            },
            cancel: () => {
              sending = false;
              reject(new Error('Stream closed before event consumption'));
            },
          };
          notify();
        });
      });
    })
    .catch((error) => {
      failure = { error };
    })
    .finally(() => {
      done = true;
      notify();
    });
  try {
    while (true) {
      signal.throwIfAborted();
      if (slot) {
        const current = slot;
        slot = undefined;
        let consumed = false;
        try {
          yield current.event;
          consumed = true;
        } finally {
          if (consumed) current.release();
          else current.cancel();
        }
      } else if (done) {
        if (failure) throw failure.error;
        return;
      } else
        await new Promise<void>((resolve) => {
          wake = resolve;
        });
    }
  } finally {
    closed = true;
    rejectSend?.(new Error('Stream closed'));
    signal.removeEventListener('abort', abort);
    void producer;
  }
}

接口参考、使用示例与开发指南。