Функциональный JavaScriptФункции-декораторыmedium

Обработка ошибок как в Go

Так выглядит код на языке Go:

func getIDs() (ids []int, err error) { resp, err := http.Get("http://localhost:9874/people/ids") if err != nil { return nil, fmt.Errorf("error fetching ids: %v", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("error reading response body: %v", err) } err = json.Unmarshal(body, &ids) return }

Обратите внимание, как здесь обрабатываются ошибки:

resp, err := http.Get("http://localhost:9874/people/ids") body, err := ioutil.ReadAll(resp.Body)

В Go не используется try-catch. Вместо этого функция возвращает два значения — результат работы и ошибку (если ошибки нет, ошибка равна null).

Кстати, похожим образом обрабатываются ошибки в JS при работе с асинхронностью (см. compose-callback).

Что нужно сделать

Пусть у нас есть функции, которые бросают ошибки.

function sum(a, b) { if (typeof a !== "number" || typeof b !== "number") { throw new Error("Invalid arguments"); } return a + b; } function double(x) { if (typeof x !== "number") { throw new Error("Invalid argument"); } return x * 2; }

Как вызвать эти функции безопасно? Например, мы хотим, чтобы функция foo(a, b) считала (a + b) × 2, вызывая sum и double. Если функции вызываются корректно, foo возвращает число. Если с ошибками — NaN.

function foo(a, b) { let s; try { s = sum(1, 2); } catch (e) { return NaN; } try { return double(s); } catch (e) { return NaN; } }

Реализуйте функцию wrap, которая трансформирует функции так, чтобы они работали в стиле Go.

Функция должна возвращать массив:

  • Если исходная функция завершилась успешно, новая функция возвращает массив из двух элементов: null (обозначат отсутствие ошибки) и результат работы функции
  • Если исходная функция бросила ошибку, новая функция возвращает массив из одного элемента — ошибки.
const wrappedSum = wrap(sum); const wrappedDouble = wrap(double); function foo(a, b) { const [e1, s] = wrappedSum(1, 2); if (e1 !== null) { return NaN; } const [e2, res] = wrappedDouble(s); if (e2 !== null) { return NaN; } return res; }