From 49b578852df5af9936afb34a53f9d41eb9b34c59 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 6 Mar 2023 12:24:55 +0100 Subject: [PATCH] fix: deal with fast consecutive promise resolutions when streaming fixes #9330 --- .changeset/strange-garlics-pump.md | 5 +++++ packages/kit/src/utils/streaming.js | 17 ++++++++++++----- packages/kit/src/utils/streaming.spec.js | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 .changeset/strange-garlics-pump.md create mode 100644 packages/kit/src/utils/streaming.spec.js diff --git a/.changeset/strange-garlics-pump.md b/.changeset/strange-garlics-pump.md new file mode 100644 index 000000000000..54207bbc4e41 --- /dev/null +++ b/.changeset/strange-garlics-pump.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: deal with fast consecutive promise resolutions when streaming diff --git a/packages/kit/src/utils/streaming.js b/packages/kit/src/utils/streaming.js index f5fcce837c1d..27d98d06d4fd 100644 --- a/packages/kit/src/utils/streaming.js +++ b/packages/kit/src/utils/streaming.js @@ -23,22 +23,29 @@ function defer() { * }} */ export function create_async_iterator() { - let deferred = defer(); + let deferred = [defer()]; return { iterator: { [Symbol.asyncIterator]() { return { - next: () => deferred.promise + next: async () => { + const next = await deferred[0].promise; + deferred.shift(); + return next; + } }; } }, push: (value) => { - deferred.fulfil({ value, done: false }); - deferred = defer(); + deferred[deferred.length - 1].fulfil({ + value, + done: false + }); + deferred.push(defer()); }, done: () => { - deferred.fulfil({ done: true }); + deferred[deferred.length - 1].fulfil({ done: true }); } }; } diff --git a/packages/kit/src/utils/streaming.spec.js b/packages/kit/src/utils/streaming.spec.js new file mode 100644 index 000000000000..ccee5a99fa87 --- /dev/null +++ b/packages/kit/src/utils/streaming.spec.js @@ -0,0 +1,20 @@ +import { test } from 'uvu'; +import * as assert from 'uvu/assert'; +import { create_async_iterator } from './streaming.js'; + +test(`works with fast consecutive promise resolutions`, async () => { + const iterator = create_async_iterator(); + + Promise.resolve(1).then((n) => iterator.push(n)); + Promise.resolve(2).then((n) => iterator.push(n)); + Promise.resolve().then(() => iterator.done()); + + const actual = []; + for await (const value of iterator.iterator) { + actual.push(value); + } + + assert.equal(actual, [1, 2]); +}); + +test.run();