Checkpoint: Preview Requests

The Course
•
4 min read

Apply the ownership rule to previews

Write createPreview(load, publish), returning an async show(key) function. Each call publishes “loading”. Only the latest call may publish its resolved string or caught error message. An older completion must remain invisible, even if it fails. This small brief does not require cancellation or disposal; those are extension requirements.

Use two deferred promises to complete the newer request first and the older one last. Record publications in an array. Check the final publication and confirm the old value is absent. Repeat with an old rejection after a newer success. Looking only at the happy path does not verify the contract.

The starter supplies deferred so you can concentrate on ownership. Spend the checkpoint time on the first ordering test; if you need more time for the rejection variation, finish it before moving on. Never replace a controlled schedule with “wait 500 ms and hope.”

Predict and trace

Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.

Predict, then run JavaScript
let current = 0;
const old = ++current;
const recent = ++current;

console.log(old === current);
console.log(recent === current);
Check your prediction
false
true

A generation identifies intent order independently of finish order.

Acceptance cases before you code

Write a small test plan before implementing latest preview lifetime. These cases extend the brief; they are not a second worked solution. Predict the expected behavior independently, then test through the public function. A good ordinary example and a good boundary example should catch different possible mistakes.

Case to tryWhat your result should demonstrate
Newer success before older successKeep the newer displayed value
Older failure after newer successIgnore the stale failure too
Old completion while the newer request is loadingDo not publish the stale result or end the newer loading state

After the core task passes, deliberately break one rule and identify the case that notices it. Restore the implementation and explain the failure in terms of the contract, not the number of assertions. If a case requires a concept you have not recalled, revisit the relevant lesson before opening the solution.

Build it yourself

Exercise

Checkpoint: Preview Requests: practise

Implement createPreview and run the newer-success-before-older-success scenario. Print the recorded messages, ending in new.

Your working space JavaScript
function deferred() {
  let resolve;
  const promise = new Promise(done => {
    resolve = done;
  });

  return { promise, resolve };
}
// Add createPreview and an ordering test.
Hint 1: the idea

Capture a token before awaiting, then guard both success and catch publications.

Hint 2: a first step

Keep the counter inside createPreview and increment it for each show call.

Show one solution
async function main() {
  function deferred() {
    let resolve;
    const promise = new Promise(done => {
      resolve = done;
    });

    return { promise, resolve };
  }

  function createPreview(load, publish) {
    let generation = 0;

    return async function show(key) {
      const mine = ++generation;

      publish("loading");

      try {
        const value = await load(key);

        if (mine === generation) {
          publish(value);
        }
      } catch (error) {
        if (mine === generation) {
          publish(error.message);
        }
      }
    };
  }

  const old = deferred();
  const recent = deferred();
  const messages = [];
  const show = createPreview(
    key => (key === "old" ? old.promise : recent.promise),
    text => messages.push(text)
  );
  const a = show("old");
  const b = show("recent");

  recent.resolve("new");
  await b;
  old.resolve("old");
  await a;

  if (messages.includes("old")) {
    throw new Error("stale publication");
  }

  console.log(messages.join(", "));
}

main();
loading, loading, new

Extend deferred with reject and test stale failure. Then specify cancel: it must invalidate a token even when no new show call replaces it.

Test a changed requirement

Extend deferred with reject and test stale failure. Then specify cancel: it must invalidate a token even when no new show call replaces it.

Explain before moving on

Why is guarding only the success path incomplete? Does ignoring a stale result stop the underlying request?

Was this article helpful?

Your response is saved on this device.