说再见 Trycatch Hell

2025-05-28

说再见 Trycatch Hell

大家好!可能是因为文章标题才来这里的,我猜你们在处理错误时遇到了一些问题async/await。在这篇文章中,你将学习一个避免trycatch 地狱的技巧,但在此之前,有必要了解一些历史。

回调的历史。

曾几何时,开发人员必须处理需要一段时间的任务,而我们检查任务是否完成的方式是通过回调。

回调只不过是任务完成(无论是成功还是错误)时执行的函数。在此之前,回调并没有什么不好。但当这些回调反过来执行其他函数时,问题就出现了。这时,可怕的事情就发生了。

动画回调地狱

因此,Promise 应运而生,作为解决这个问题的解决方案。

承諾。

Promise 是表示流程完成的对象,可以是失败(拒绝)或成功(解决)。此外,让我们添加这个美化功能。

Promise 与 Callback 的比较

一切都显得如此神奇,直到……

图片trycatch地狱

使用async await使得代码更易读,看起来更美观,但是它有一个问题,就是如果promise失败了,它就会停止我们系统的流程,所以有必要处理错误。

但是当使用 trycatch 处理这些问题时,我们会失去可读性,但别担心,这些现在已经结束了,我亲爱的朋友。

如何实施。

首先,我们要模拟一个整体。我们开始吧。

定义一些接口,并添加测试内容。



interface Note {
  id: number;
  name: string;
}

interface Query {
  [key: string]: any;
}

const notes: Note[] = [
  {
    id: 1,
    name: "Megadeth",
  },
  {
    id: 2,
    name: "Korn",
  },
];



Enter fullscreen mode Exit fullscreen mode

我们定义一些函数。



async function update(id: number, data: Omit<Note, "id">, options: Query): Promise<Note> {
  const index: number = notes.findIndex(n => n.id === id);
  if (index < 0) throw new Error("Note does not exist");

  const updated: Note = { id, ...data };
  notes.splice(index, 1, updated);
  return updated;
};

async function remove(id: number, options: Query): Promise<Note> {
  const index: number = notes.findIndex(n => n.id === id);
  if (index < 0) throw new Error("Note does not exist.");

  const note: Note = notes[index];
  notes.splice(index, 1);
  return note;
};



Enter fullscreen mode Exit fullscreen mode

我们定义我们的承诺处理程序。



async function promHandler<T>(
  prom: Promise<T>
): Promise<[T | null, any]> {
  try {
    return [await prom, null];
  } catch (error) {
    return [null, error];
  }
}


Enter fullscreen mode Exit fullscreen mode

该函数接收一个 promise 作为参数,然后我们在 trycatch 中执行该 promise,以处理错误,并返回一个数组,其中第一个索引 [0] 将是响应或结果,第二个索引 [1] 将是错误。

注意:您可能会看到一个T,这是必要的,因为我们需要随时知道数据的类型,它们被称为泛型,如果您需要了解更多信息,请点击以下链接:https://www.typescriptlang.org/docs/handbook/2/generics.html

现在,我们仅使用我们的处理程序。



  const [updated, err] = await promHandler(
    update(1, { name: "Mudvayne" }, {})
  );
  // updated -> {id: 1, name: "Mudvayne"}
  // err -> null

  const [removed, error] = await promHandler(remove(4, {}));
  // removed -> null
  // error -> Error "Does not exist."



Enter fullscreen mode Exit fullscreen mode

现在我问你,看起来好些了吗?

太好了,我们已经知道如何避免trycatch地狱了,但这只使用承诺,那么同步函数呢?

处理同步功能。

我们将以前的功能转换为同步的。



function update(id: number, data: Omit<Note, "id">, options: Query): Note {
  // ...
};

function remove(id: number, options: Query): Note {
  // ...
};


Enter fullscreen mode Exit fullscreen mode

我们定义同步函数处理程序。



function funcHandler<T extends any[], K>(
  func: (...args: T) => K,
  ...params: T
): [K | null, any] {
  try {
    return [func(...params), null];
  } catch (error) {
    return [null, error];
  }
}


Enter fullscreen mode Exit fullscreen mode

说明:此函数与前一个函数略有不同,因为在此函数中,我们必须为其提供函数(不执行)和参数。

这个函数将包含两个泛型,其中T表示函数接收的参数,K表示函数返回的值。此外,我们还使用了展开语法。由于我们不知道最终能到达的参数数量,我们将利用这三个魔法点 (...) ✨

现在,我们执行前面的流程,第一个索引,结果;第二个索引,错误。好了!

我们执行这些操作。



  const [updated, err] = funcHandler(update, 1, { name: "Mudvayne" }, {});
  // updated -> {id: 1, name: "Mudvayne"}
  // err -> null

  const [removed, error] = funcHandler(remove, 6, {});
  // removed -> null
  // error -> Error "Does not exist."



Enter fullscreen mode Exit fullscreen mode

太好了,我们不再需要努力让我们的代码看起来更易读,而且,我们可以重复使用句柄。

你知道,如果你有东西可以贡献,一个问题,一个改进,你可以在评论中贡献,如果它有用,请留下你的反应,这让我很高兴。

在社交网络上关注我。

文章来源:https://dev.to/ivanzm123/say-goodbye-trycatch-hell-336o
PREV
创建动态 README.md 文件
NEXT
30 个最基本的数据结构和算法的完整介绍