说再见 Trycatch Hell
大家好!可能是因为文章标题才来这里的,我猜你们在处理错误时遇到了一些问题async/await
。在这篇文章中,你将学习一个避免trycatch 地狱的技巧,但在此之前,有必要了解一些历史。
回调的历史。
曾几何时,开发人员必须处理需要一段时间的任务,而我们检查任务是否完成的方式是通过回调。
回调只不过是任务完成(无论是成功还是错误)时执行的函数。在此之前,回调并没有什么不好。但当这些回调反过来执行其他函数时,问题就出现了。这时,可怕的事情就发生了。
因此,Promise 应运而生,作为解决这个问题的解决方案。
承諾。
Promise 是表示流程完成的对象,可以是失败(拒绝)或成功(解决)。此外,让我们添加这个美化功能。
一切都显得如此神奇,直到……
使用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",
},
];
我们定义一些函数。
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;
};
我们定义我们的承诺处理程序。
async function promHandler<T>(
prom: Promise<T>
): Promise<[T | null, any]> {
try {
return [await prom, null];
} catch (error) {
return [null, error];
}
}
该函数接收一个 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."
现在我问你,看起来好些了吗?
太好了,我们已经知道如何避免trycatch地狱了,但这只使用承诺,那么同步函数呢?
处理同步功能。
我们将以前的功能转换为同步的。
function update(id: number, data: Omit<Note, "id">, options: Query): Note {
// ...
};
function remove(id: number, options: Query): Note {
// ...
};
我们定义同步函数处理程序。
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];
}
}
说明:此函数与前一个函数略有不同,因为在此函数中,我们必须为其提供函数(不执行)和参数。
这个函数将包含两个泛型,其中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."
太好了,我们不再需要努力让我们的代码看起来更易读,而且,我们可以重复使用句柄。
你知道,如果你有东西可以贡献,一个问题,一个改进,你可以在评论中贡献,如果它有用,请留下你的反应,这让我很高兴。