AniUI Academy

Await without try/catch

easyAsync & Promises+150 XPPractice

Deeply nested try/catch blocks around every await make request handlers hard to read. A common alternative, borrowed from Go, is to have the call return both the error and the value and let the caller check which one is set.

Implement safeAwait(value). It accepts a promise or a plain value and returns a promise that **always fulfils** with a two-element array. If the input fulfils with v, resolve with [null, v]. If it rejects with e, resolve with [e, null]. A non-promise input is treated as an already-fulfilled value. The returned promise must never reject.

Arguments

valuePromise<T> | T
A promise or a plain value.

Returns

Promise<[Error | null, T | null]> — A promise that always fulfils with a two-element tuple: [null, value] on success, [error, null] on failure.

Examples

const [err, value] = await safeAwait(Promise.resolve(7));
// err === null, value === 7

Successful inputs come back with a null error slot.

const failing = Promise.reject(new Error("nope"));
failing.catch(() => {});
const [err, value] = await safeAwait(failing);
// err.message === "nope", value === null

A rejection becomes a tuple — no try/catch needed.

const [err, value] = await safeAwait(42);
// err === null, value === 42

Non-promise inputs are wrapped.

What it has to do

  • Always fulfil with an array of exactly two elements.
  • Use null — not undefined — for the empty slot.
  • Accept plain values as well as promises.
  • Never reject, whatever the input does.

Notes

  • Promise.resolve(value).then(onFulfilled, onRejected) handles the plain-value case for free.
  • Use null (not undefined) in the empty slot so destructuring with defaults behaves predictably.

Stuck? The javascript course covers everything this challenge needs.

Try it yourself
Loading playground...
4 tests · +150 XP

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.