stream: async iterator destroy compat
async iterator should not depend on internal API for better compat with streamlike objects. PR-URL: https://github.com/nodejs/node/pull/29176 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
2fc87685d9
commit
4e188b3c63
@ -110,17 +110,26 @@ const ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf({
|
|||||||
},
|
},
|
||||||
|
|
||||||
return() {
|
return() {
|
||||||
// destroy(err, cb) is a private API.
|
|
||||||
// We can guarantee we have that here, because we control the
|
|
||||||
// Readable class this is attached to.
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this[kStream].destroy(null, (err) => {
|
const stream = this[kStream];
|
||||||
if (err) {
|
|
||||||
reject(err);
|
// TODO(ronag): Remove this check once finished() handles
|
||||||
return;
|
// already ended and/or destroyed streams.
|
||||||
}
|
const ended = stream.destroyed || stream.readableEnded ||
|
||||||
|
(stream._readableState && stream._readableState.endEmitted);
|
||||||
|
if (ended) {
|
||||||
resolve(createIterResult(undefined, true));
|
resolve(createIterResult(undefined, true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finished(stream, (err) => {
|
||||||
|
if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(createIterResult(undefined, true));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
stream.destroy();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AsyncIteratorPrototype);
|
}, AsyncIteratorPrototype);
|
||||||
|
@ -486,5 +486,46 @@ async function tests() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// AsyncIterator return should end even when destroy
|
||||||
|
// does not implement the callback API.
|
||||||
|
|
||||||
|
const r = new Readable({
|
||||||
|
objectMode: true,
|
||||||
|
read() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const originalDestroy = r.destroy;
|
||||||
|
r.destroy = (err) => {
|
||||||
|
originalDestroy.call(r, err);
|
||||||
|
};
|
||||||
|
const it = r[Symbol.asyncIterator]();
|
||||||
|
const p = it.return();
|
||||||
|
r.push(null);
|
||||||
|
p.then(common.mustCall());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// AsyncIterator return should not error with
|
||||||
|
// premature close.
|
||||||
|
|
||||||
|
const r = new Readable({
|
||||||
|
objectMode: true,
|
||||||
|
read() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const originalDestroy = r.destroy;
|
||||||
|
r.destroy = (err) => {
|
||||||
|
originalDestroy.call(r, err);
|
||||||
|
};
|
||||||
|
const it = r[Symbol.asyncIterator]();
|
||||||
|
const p = it.return();
|
||||||
|
r.emit('close');
|
||||||
|
p.then(common.mustCall()).catch(common.mustNotCall());
|
||||||
|
}
|
||||||
|
|
||||||
// To avoid missing some tests if a promise does not resolve
|
// To avoid missing some tests if a promise does not resolve
|
||||||
tests().then(common.mustCall());
|
tests().then(common.mustCall());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user