close()
Environment: client & server.
Manually close Telefunc streams.
The
close()function is one of several ways to manually close streams — see all methods at How to close.
You usually don't need to manually close streams yourself — see: When to close.
For listening to streams closing, see: API >
onClose().
When to close
A stream automatically closes itself when the client stops using it.
How does it work? When a
streamobject becomes unreachable (the client drops all references to it), the browser's garbage collector clears the stream object and the stream automatically closes itself.
You therefore usually don't have to manually close streams yourself.
That said, there is a short delay (typically a few seconds) between when the client stops using the stream and when the stream is closed. (The garbage collector doesn't always immediately clear unused objects.)
For example:
// Chat.jsx
// Environment: client
import { useEffect, useState } from 'react'
import { onChat } from './Chat.telefunc'
function Chat() {
const [messages, setMessages] = useState([])
useEffect(() => {
const open = onChat() // Promise<{ channel }>
open.then(({ channel }) => {
channel.listen((msg) => setMessages((prev) => [...prev, msg]))
})
// Optional:
const clear = () => open.then(({ channel }) => channel.close())
return clear
}, [])
return (
<ul>
{messages.map((m, i) => (
<li key={i}>{m}</li>
))}
</ul>
)
}// Chat.tsx
// Environment: client
import { useEffect, useState } from 'react'
import { onChat } from './Chat.telefunc'
function Chat() {
const [messages, setMessages] = useState<string[]>([])
useEffect(() => {
const open = onChat() // Promise<{ channel }>
open.then(({ channel }) => {
channel.listen((msg) => setMessages((prev) => [...prev, msg]))
})
// Optional:
const clear = () => open.then(({ channel }) => channel.close())
return clear
}, [])
return <ul>{messages.map((m, i) => <li key={i}>{m}</li>)}</ul>
}// Clock.jsx
// Environment: client
import { useEffect, useState } from 'react'
import { onClock } from './Clock.telefunc'
function Clock() {
const [n, setN] = useState(0)
useEffect(() => {
const clock = onClock() // long-lived AsyncGenerator
;(async () => {
for await (const tick of clock) setN(tick)
})()
// Optional:
const clear = () => void clock.return() // a running loop won't stop on its own
return clear
}, [])
return <p>{n}</p>
}// Clock.tsx
// Environment: client
import { useEffect, useState } from 'react'
import { onClock } from './Clock.telefunc'
function Clock() {
const [n, setN] = useState(0)
useEffect(() => {
const clock = onClock() // long-lived AsyncGenerator
;(async () => {
for await (const tick of clock) setN(tick)
})()
// Optional:
const clear = () => void clock.return() // a running loop won't stop on its own
return clear
}, [])
return <p>{n}</p>
}Returning clear is optional: if you don't, the stream still closes itself automatically after React unmounts the component — the garbage collector clears the stream object and then the stream closes itself.
That said, if you want the stream to close as soon as possible, manually close it yourself — return clear in this example.
How to close
From the client, you can manually close a stream early with close() — or simply stop reading: break out of a for await, reader.cancel() a ReadableStream, or channel.close() a channel.
There's one catch-all API, close(), plus several per-stream-primitive APIs.
| API | Side | Graceful / immediate | Closes |
|---|---|---|---|
close(value) | client | Graceful | Everything in the returned value (walked recursively) |
gen.return() / break | client | Graceful | One AsyncGenerator |
reader.cancel() | client | Graceful | One ReadableStream |
channel.close() | client & server | Graceful | One Channel / BroadcastChannel (both ends) |
channel.abort(value?) | client & server | Immediate | One Channel / BroadcastChannel, with an abort value |
abort(call) | client | Immediate | The in-flight call and any channels it opened |
withContext(fn, { signal }) | client | Immediate | The call and any channels it opened, via an AbortSignal |
Graceful: flush buffered data, then close.
Immediate: cancel in-flight work.
close()
Gracefully closes all streams: in one call, it closes every stream the telefunction call opened.
// Environment: client
import { close } from 'telefunc/client'
import { onLoadDashboard } from './Dashboard.telefunc'
const result = await onLoadDashboard()
// Read what you need...
const { value } = await result.stream.next()
// Then close everything at once
close(result)abort()
To stop a call immediately instead of gracefully, use abort() — the request is cancelled, and the pending call rejects with an Abort error (or, if you're mid-stream, that error surfaces on the next read instead):
// Environment: client
import { abort } from 'telefunc/client'
const call = onLoadDashboard()
abort(call) // cancels the in-flight callTo abort via an AbortSignal instead, use withContext(fn, { signal }).