It Does Not Ask — Why Polling Is Worse Than Wasteful
5 minThrough part 4, knowing the latest value meant asking — every second, or when a person refreshed.
Subscribe
client.onResourceUpdated((uri) {
// The notification says only that it changed. Read to learn what to.
seen.add(uri);
stdout.writeln('notified: $uri');
});
await client.subscribeResource('desk://waiting');Then make the value change.
await client.callTool('desk.admit', {'count': 1});subscribed to desk://waiting
notified: desk://waiting
after the notification, reading gives {waiting: 2}
notifications received: 1The notification carries only the uri
The handler receives one uri. How many are waiting does not arrive. Server part 6 covered why no value rides along; on the receiving side it means you have to read.
final now = await client.readResource('desk://waiting');One more round trip looks like a loss, and it is always right. However many notifications arrive and in whatever order, the value at the moment you read is the current one.
The real problem with polling
Polling is usually rejected on cost. Knocking on the server every second is wasteful.
That is secondary. The real problem is that you cannot see between two polls.
09:00:00 poll → waiting 3
09:00:00.4 two admitted → waiting 1
09:00:00.7 one arrives → waiting 2
09:00:01 poll → waiting 2The screen went from 3 to 2. It never saw the moment it was 1. If only the final value matters, fine — but a rule like "alert when it reaches zero" will never fire.
Shortening the interval does not remove this. It narrows it. And the narrower it gets, the more the waste grows.
Unsubscribe when done
await client.unsubscribeResource('desk://waiting');When the screen closes, drop the subscription. Leave it and the server keeps sending to nobody.
The ESP32 in the real-board piece put this inside the screen definition — subscribe on onReady, release on onDestroy. With the lifecycle written into the screen, the client cannot forget.
Verification — polling fails
grep -q 'notified: desk://waiting' captures/s5.txt || die "no notification arrived"
grep -q 'notifications received: 1' captures/s5.txt || die "wrong notification count"
grep -q 'reading gives {waiting: 2}' captures/s5.txt || die "the read after the notification was stale"
# Polling would show up as a timer; the claim is that there is none.
grep -qE 'Timer|periodic' bin/step5.dart && die "it is polling, not subscribing"A Timer or periodic in the code fails it. Because from the result alone, polling and subscribing look identical — both put 2 on the screen.
Counting notifications is for the same reason. Zero means none arrived; several means a duplicate subscription.
Five steps done
step1 connected to Course 1.0.0
step2 tools: desk.admit
resources: ui://desk, desk://waiting
step3 admit 1 -> {waiting: 2}
admit 99 -> isError=true "only 2 waiting"
step4 ui://desk — 546 B, 6 lines, type "page", title "Desk"
step5 notifications received: 1 · after the notification, reading gives {waiting: 2}
5 steps · each checked against its own claim · driven against the course serverThere is no mock server. All five steps start and attach to the server built in the server course. So when the two tracks drift, it shows up here — and in part 3, it did.
Run it yourself
cd content/sample/course-client
dart pub get
bash verify.sh # all five steps
dart run bin/step5.dartWhat to take
onResourceUpdatedthensubscribeResource— hang the handler before subscribing- Read after the notification — it carries only a uri
- A no-polling check — the results look the same, so read the code
Next track
Server and client are standing. Next is the screen itself — how one blob of JSON becomes one.
Run the sample
cd course-client dart pub get dart run bin/step5.dart