proposal-try-expressions
proposal-try-expressions copied to clipboard
Proposal for simpler exception handling when using functions and Promises in ECMAScript
try expressions
Proposal for simpler error handling
when using functions and Promises in ECMAScript
Summary
The current try...catch
error handling pattern leads to uncaught exceptions when dealing with promises. This is a new try
syntax to combine a Promise's value and error or wrap an expression in a try...catch
with a single return type.
let [json, jsonErr] = try JSON.parse('{}')
let [value, err] = try await fetch()
// instead of
let json, jsonErr, value, err
try {
json = JSON.parse('{}')
} catch (_jsonErr) {
jsonErr = _jsonErr
}
try {
value = await fetch()
} catch (_err) {
err = _err
}
It's backwards-compatible with existing
try...catch
usage, functions and expressions.
Return Type
interface TryExpressionReturn {
[0]: any
[1]: Error
}
Example
async function fetchUser(userId) {
let [gqlRes, gqlErr] = try await fetch(GRAPHQL_HOST + queryForUser(userId))
if (!gqlErr) return gqlRes
// If the GraphQL server doesn't respond properly, use fallback API
let [apiRes, apiErr] = try await fetch(`${V1_API_HOST}/v1/users/${userId}`)
// If the fallback API fails, throw the error
if (apiErr) throw apiErr
return apiRes
}
// Or for error reporting
let [, err] = try importantFn()
reprotError(err)
reportError((try importantFn())[1])
Design Decisions
-
Array return type. This removes unnecessary opinion and bytes from source compared to using an Object.
- 👍
let [myValue, myError] = try await fn()
- 👎
let { value: myValue, error: myError } = try await fn()
- 👍
-
Array order inspired by Golang. This seems to make more sense instead of callback-style with error as the first argument, e.g.
res, err := http.Get(API_HOST)
Alternatives
Status Quo
async/await
async function fetchUser(userId) {
try {
return await fetch(GRAPHQL_HOST + queryForUser(userId))
} catch (gqlErr) {
try {
return await fetch(`${V1_API_HOST}/v1/users/${userId}`)
} catch (apiErr) {
throw apiErr
}
}
}
async/await + catch
async function fetchUser(userId) {
let gqlErr, gqlErr
gqlRes = await fetch(GRAPHQL_HOST + queryForUser(userId)).catch(err => gqlErr = err)
if (gqlErr) {
return await fetch(`${V1_API_HOST}/v1/users/${userId}`)
}
return gqlRes
}
Userland Modules
Adoption Strategy
- This proposal is implemented as a Babel plugin to compile try expressions down to valid ECMAScript
- Backwards-compatible with existing exception handling and Promise spec
- Open to community for comment and testing