在 JavaScript 中是否有一种设计模式用于编写可以有条件地抛出异常或捕获异常以返回值的函数?

问题描述 投票:0回答:1

有时需要调用函数并直接处理异常(使用 try/catch),而其他时候最好调用 same 函数并接收

null
false
如果它会否则失败。

这个想法或用例类似于 ActiveRecord 中的 Rails,您可以选择调用

User.find(1)
User.find!(1)
——如果找不到,前者将返回
nil
,而后者将引发异常。

问题: 我是这些功能的作者,所以我可以以任何方式设计它。这个想法在 javascript 中有规定的模式吗?


一个想法是模仿 ActiveRecord 中所做的事情:

// returns API data or bubbles-up exception
function getDataFromAPI() {
  const response = callApi(); // function throws error if not 200
  return response.data;
}

// returns API data or null
function getDataFromAPI_() {
  try {
    return getDataFromAPI();
  } catch(e) {
    return null;
  }
}

也许另一种方法是为 try/catch 创建一个通用包装器,尽管这个例子没有考虑参数:

// returns API data, but will raise an exception if
// `response` has no `data` property...
function getDataFromAPI() {
  const response = callApi();
  return response.data;
}

// return function or null
function nullIfError(func) {
  try {
    return func();
  } catch(e) {
    return null;
  }
}

nullIfError(getDataFromAPI)

或者,添加一个参数以有条件地改变它的行为,但我不喜欢它总是包含在 try/catch 中......

function getDataFromAPI(throwError = true) {
  try {
    const response = callApi();
    return response.data;
  } catch(e) {
    if (throwError) throw(e);
    else return null;
  }
}
javascript function design-patterns try-catch control-flow
1个回答
0
投票

即使没有真正建立的模式,也可以引入原型和/或非原型实现可能需要的函数/方法修饰符(例如

afterFinally
afterThrowing
after
before
around 
) 允许在此类修改后的函数/方法的调用/应用/执行时间根据其参数、返回值和上下文来拦截、自省和操作函数/方法的控制流。

至于 OP 的用例,

afterThrowing
修饰符 非常方便。

下一个提供的示例代码显示了它的实现和用法。

function deliverData() {
  return { data: { foo: "bar "} };
}
function throwError() {
  throw new Error('API not available.');
}

function callMockedApi() {
  return [deliverData, throwError][Math.floor(Math.random() * 2)]();
}

function getDataFromAPI() {
  const response = callMockedApi();
  return response.data;
}
const getDataFromAPI_ = getDataFromAPI.afterThrowing(() => null);

console.log(getDataFromAPI_());
console.log(getDataFromAPI());
<script>
function isFunction(value) {
  return (
    'function' === typeof value &&
    'function' === typeof value.call &&
    'function' === typeof value.apply
  );
}
function getSanitizedTarget(value) {
  return value ?? null;
}

function afterThrowing(handler, target) {
  target = getSanitizedTarget(target);

  const proceed = this;
  return (
    isFunction(handler) &&
    isFunction(proceed) &&

    function afterThrowingType(...argumentArray) {
      const context = getSanitizedTarget(this) ?? target;

      let result;
      try {
        result = proceed.apply(context, argumentArray);
      } catch (exception) {
        result = handler.call(context, exception, argumentArray);
      }
      return result;
    }
  ) || proceed;
}

Reflect.defineProperty(Function.prototype, 'afterThrowing', {
  configurable: true,
  writable: true,
  value: afterThrowing,
});
</script>

有关此主题的更多信息,请阅读 ...

© www.soinside.com 2019 - 2024. All rights reserved.