axios 在Typescript中处理Promise捕获

stszievb  于 2023-10-18  发布在  iOS
关注(0)|答案(2)|浏览(174)

我有一个基于promise的API服务,它从我的后端请求数据。它也有自己的错误捕获,所以我不必到处写它。当它这样写的时候:

BackendService.ts

...
getTasks() {
    return axios.get('/api/tasks')
        .then((response) => {
            const {
                tasks
            }: {
                tasks: tasksType
            } = response.data;
            return tasks;
        })
        .catch((error) => console.log(error));
}
...

请点击.tsx

...
const getTasks = () => {
    backendService.getTasks()
        .then((tasks: tasksType) => {
            const filteredTasksData = filterAPIDataForState(tasks);

            addTasks({
                tasks: filteredTasksData
            });
        })
}
...

我得到以下错误:

TS2345: Argument of type '(tasks: tasksType) => void'
is not assignable to parameter of type '(value: void | tasksType) => void | PromiseLike<void>'.Types of parameters 'tasks'
and 'value'
are incompatible.Type 'void | tasksType'
is not assignable to type 'tasksType'.Type 'void'
is not assignable to type 'TaskInterface[]'.

我猜这是因为catch,它可以使Promise不返回任何东西(因为console.log)。如果我给予getTasksEntries.tsx它自己的catch处理程序,并从BackendService.ts getTasks中删除它,它就可以工作。
如果出现错误,Typescript不应该知道Entries.tsx中的.then()不会运行,因为已经有一个catch处理这种情况了吗?

wj8zmpe1

wj8zmpe11#

如果出现错误,则.then()在.tsx中不会运行,因为已经有一个catch处理这种情况?
这并不完全正确。
backendService.ts文件中getTasks方法中的catch块返回undefined和**,而catch块返回值**,而不是:

  • 抛出一个值
  • 抛出错误,或
  • 返回被拒绝的promise

在调用代码中,不是调用catch块,而是调用**then块**。
这是因为backendService.ts文件中的getTasks方法返回的Promise依赖于以下内容:

  • 如果axios.get(...)返回的Promise满足,那么您在then(...)块中执行的操作
  • 如果axios.get(...)返回的Promise被拒绝,那么在catch(...)块中执行的操作

在您的例子中,如果axios.get(...)返回的Promise满足,那么then(...)块将执行,因为它只返回tasks,所以backendService.ts文件中的getTasks方法返回的Promise满足,导致调用代码中的then(...)块,即在Entries.tsx文件中。
如果axios.get(...)返回的Promise被拒绝,则catch(...)块将执行。由于getTasks方法中的catch(...)块只是记录错误,因此getTasks方法返回的Promise满足undefined的值,这将导致调用代码中调用then(...)块,即在Entries.tsx文件中。
请看下面的例子来理解这一点。

function getData() {
  // incorrect url which will lead to response.ok being false
  const url = 'https://jsonplaceholder.typicode.com/todo/1';
  return fetch(url)
          .then(response => {
            if (response.ok) {
              return response.json();
            } else {
              throw new Error();
            }
          })
          .catch(error => console.log('catch block in getData function')); 
}

getData()
  .then(data => console.log('then block ran'))
  .catch(error => console.log('error block ran'));

在上面的代码片段中,由于API URL不正确,then块中的response.ok为false,因此从同一函数中的catch块捕获的then块中抛出错误。由于这个catch块只是记录一条消息并隐式返回undefined,因此getData函数返回的Promise满足undefined的值。因此,在调用getData函数的代码中执行的不是catch块,而是then块。
如果你不知道这一点,那么你可能会惊讶地看到这种行为,但这就是promise如何与catch块一起工作的。这种行为的原因是,如果你有一个promise链,它有一个以上的catch块,如下所示:

fetch(...)
  .then(...)
  .catch(...)   
  .then(...)
  .then(...)
  .catch(...);

那么如果第一个catch块捕获了一个从它之前链接的任何方法抛出的错误,那么这个catch块可以做以下两件事之一:

  • 抛出错误,然后调用promise链中的下一个catch
  • 处理错误并返回一些值

如果第一个catch块正常返回,则catch块返回的promise将满足catch块的返回值,然后该值成为promise链中下一个then块的回调函数的输入。因此,promise链继续运行,而不是在第一个catch块执行后立即停止。
回到你的代码,当catch块在backendService.ts文件中的getTasks方法中执行时,它记录消息并返回undefined,然后导致调用Entries.tsx文件中的then块,而不是catch块,这就是为什么你会收到typescript对你代码的抱怨。

解决方案

您可以使用以下选项之一来解决此问题:

  • 抛出backendService.ts文件中getTasks方法的catch(...)块中捕获的错误,以便拒绝getTasks方法返回的Promise,而不是使用undefined的值来实现。
  • 删除backendService.ts文件中getTasks函数中的catch块,并在调用getTasks方法的代码中添加catch块。

在我看来,在backendService.ts文件中不需要catch块,因为如果axios.get(...)返回的Promise被拒绝,那么如果getTasks方法中没有catch块,getTasks方法返回的Promise也会被拒绝。因此,只需从getTasks方法中删除catch(...)块,并在调用此getTasks方法的位置添加catch(...)块。

bsxbgnwa

bsxbgnwa2#

有很多选择来处理这一点
1.在BackendService.getTasks()中,只需删除.catch()并在.getTasks()中处理.catch()即可。
1.在BackendService.getTasks()中添加另一个then并返回空任务,例如.then(it => it|| [])
Axios不会在响应错误时崩溃,因此您必须正确检查响应并处理它,因为它不应该只是盲目地破坏响应对象

相关问题