I created a library for Node and the browser and want to call an external endpoint which responds with a stream. Since this stream might never end the client should be able to abort the process.
public async observe(): Promise<() => void> {
const abortController = new AbortController();
const response = await fetch('url', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: { /* ... */ },
signal: abortController.signal,
});
if (!response.ok) {
// handle error
}
setImmediate(async () => {
// parse response.body ( stream )
});
return () => {
abortController.abort();
};
}
I used setImmediate
because I must return the abort function first, otherwise this function would never reach the return statement because it keeps parsing the stream.
Unfortunately setImmediate
is not supported by browsers ( https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate?retiredLocale=de#browser_compatibility )
Does someone know what to use instead?
CodePudding user response:
There are a couple of options.
If you want a microTask you could use a Promise.
Promise.resolve().then(
() => console.log('there'));
console.log('hello');
For a normal Task, you could use setTimeout
;
setTimeout(() => console.log('there'));
console.log('hello');
There is also the requestAnimationFrame
. https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
It's been pointed out why not just use try finally
. But one issue with that, if your processing the stream in finally, then by the time the caller gets the abort
function it's too late. But rather than using something like setImmediate
, it would actually be cleaner if you just return a promise for the streaming, and the abort function together.
eg.
public async observe(): Promise<() => void> {
const abortController = new AbortController();
const response = await fetch('url', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: { /* ... */ },
signal: abortController.signal,
});
if (!response.ok) {
// handle error
}
return {
abort: () => abortController.abort(),
promise: async () => {
// parse response.body ( stream )
}
};
}
You can then call like ->
const {abort, promise} = observe();
setTimeout(() => abort(), 5000); //abort in 5 seconds
await promise;