处理打字稿中的承诺承诺

时间:2020-07-12 09:10:36

标签: javascript typescript promise axios

我有一个基于诺言的API服务,该服务从后端请求数据。它还带有它自己的错误捕获,因此我不必到处编写它。这样写的时候:

BackendService.ts

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

Entries.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[]'.

我猜这是由于捕获而导致的,这可能会使Promise不返回任何内容(由于console.log)。如果我将getTasks中的Entries.tsx设为自己的捕获处理程序,并将其从BackendService.ts getTasks中删除,它将起作用。

Typescript是否不能告诉.then()中的Entries.tsx如果发生错误就不会运行,因为已经有一个捕获来处理这种情况了?

2 个答案:

答案 0 :(得分:2)

如果出现错误,Entries.tsx中的.then()将不会运行,因为 已经有处理这种情况的陷阱了?

那不是完全正确。

catch文件中getTasks方法中的

backendService.ts块返回undefined,而catch块返回值时引发捕获的错误,而不是调用调用代码的catch块,而是调用 then

之所以会这样,是因为Promise文件中的getTasks方法返回的backendService.ts取决于以下内容:

  • 如果Promise返回的axios.get(...)完成了,那么您在then(...)块中所做的事情

  • 如果Promise返回的axios.get(...)被拒绝,那么您在catch(...)块中所做的事情

在您的情况下,如果Promise个实现返回的axios.get(...),则将执行then(...)块,因为它只返回了tasks,所以返回了Promise通过getTasks文件中的backendService.ts方法实现,导致在调用代码即then(...)文件中调用Entries.tsx块。

如果Promise返回的axios.get(...)被拒绝,则将执行catch(...)块。由于catch(...)方法中的getTasks块仅记录了错误,因此Promise方法返回的getTasks满足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不正确,response.ok块中的then为false,因此从then块中抛出了错误,{ {1}}块在同一函数中。由于此catch块仅记录一条消息并返回catch,因此undefined函数返回的Promise的值为getData。因此,undefined块不是catch块,而是在调用then函数的代码中执行。

如果您不知道这一点,那么您可能会惊讶地看到这种行为,但这就是getDataPromises块一起工作的方式。这种现象的原因是 如果您的诺言链包含多个catch块,如下所示:

catch

然后,如果第一个fetch(...) .then(...) .catch(...) .then(...) .then(...) .catch(...); 块捕获到从它之前链接的任何函数引发的错误,则此catch块可以执行以下两项操作之一:

  • 抛出错误,然后将导致最后一个catch块的调用
  • 处理错误并返回一些值

如果第一个catch块正常返回,则catch块返回的承诺将以catch块的返回值实现,然后该值成为回调函数的输入。承诺链中的下一个catch块。因此,承诺链会继续执行,而不是在第一个then块执行后立即停止。


回到您的代码,当在catch文件中的catch方法中执行getTasks块时,它将记录该消息并返回backendService.ts,然后导致调用undefined文件中的then块,而不是Entries.tsx块,这就是为什么打字稿会抱怨您的代码的原因。

解决方案

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

  • 将在catch文件的catch(...)方法的getTasks块的backendService.ts块中引发的错误扔给Promise方法返回的getTasks满足undefined的价值。

  • catch文件的getTasks函数中删除backendService.ts块,并在调用catch方法的代码中添加getTasks块。

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

答案 1 :(得分:0)

有很多方法可以解决这个问题

  1. 在BackendService.getTasks()中,只需删除.catch()并在Entries.getTasks()中处理.catch()
  2. 在BackendService.getTasks()中添加另一个,然后返回空任务,例如.then(it => it || [])

当响应错误时,Axios不会崩溃,因此您必须正确检查并处理响应,因为它不只是盲目地破坏响应对象