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

wn9m85ua  于 2023-04-19  发布在  Java
关注(0)|答案(1)|浏览(109)

有时需要调用一个函数并直接处理异常(使用try/catch),而其他时候最好调用 * 同一个 * 函数并接收nullfalse,否则会失败。
这个想法或用例类似于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创建一个通用的 Package 器,尽管这个例子没有考虑参数:

// 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)

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

function getDataFromAPI(throwError = true) {
  try {
    const response = callApi();
    return response.data;
  } catch(e) {
    if (throwError) throw(e);
    else return null;
  }
}
mzmfm0qo

mzmfm0qo1#

即使没有真实的建立的模式,也可以引入可能需要的函数/方法修饰符的原型和/或非原型实现(例如afterFinallyafterThrowingafterbeforearound),其允许根据其参数拦截、内省和操纵函数/方法的控制流,返回值和上下文在这样修改的函数/方法的调用/应用/执行时间。
至于OP的用例,afterThrowing modifier非常方便。
下面提供的示例代码显示了它的实现和用法。

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>

相关问题