处理 Typescript 中的 Promise 捕获 [英] Handle Promise Catches in Typescript

查看:43
本文介绍了处理 Typescript 中的 Promise 捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于 Promise 的 API 服务,它从我的后端请求数据.它还带有自己的错误捕获功能,所以我不必到处都写.写成这样:

I have a promise based API service that requests data from my backend. It also comes with it's own error catch, so I don't have to write it everywhere. When it's written like this:

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).如果我从 Entries.tsx 中给 getTasks 它自己的捕获处理程序并将其从 BackendService.ts getTasks 中删除,它会起作用.

I guess this is because of the catch, that could make the Promise return nothing (because of the console.log). If I give the getTasks from Entries.tsx it's own catch handler and remove it from BackendService.ts getTasks, it works.

Typescript 不应该能够告诉 Entries.tsx 中的 .then() 在出现错误时不会运行,因为已经有一个捕获处理这种情况?

Shouldn't Typescript be able to tell that the .then() in Entries.tsx would not run if there was an error, since there's already a catch handling this situation?

推荐答案

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

the .then() in Entries.tsx would not run if there was an error, since there's already a catch handling this situation?

这并不完全正确.

catch 块正在返回 undefinedcatch块返回一个值而不是抛出捕获的错误,而不是调用调用代码的catch块,then 块被调用.

catch block in getTasks method in backendService.ts file is returning undefined and when a catch block returns a value instead of throwing the caught error, instead of invoking catch block of the calling code, then block is invoked.

发生这种情况是因为 backendService.ts 文件中的 getTasks 方法返回的 Promise 依赖于以下内容:

This happens because Promise returned by getTasks method in backendService.ts file depends on the following:

  • 如果 axios.get(...) 返回的 Promise 实现,那么你在 then(...)

  • If the Promise returned by axios.get(...) fulfils then what you do in the then(...) block

如果 axios.get(...) 返回的 Promise 被拒绝,那么你在 catch(...)

If the Promise returned by axios.get(...) is rejected then what you do in the catch(...) block

在您的情况下,如果 axios.get(...) 返回的 Promise 满足,则 then(...)块将执行,因为它只返回 tasksPromisebackendService.ts 文件中的 getTasks 方法返回,满足导致调用代码中的 then(...) 块的调用,即在 Entries.tsx 文件中.

In your case, if the Promise returned by axios.get(...) fulfils, then then(...) block will execute and since it just returns the tasks, Promise returned by getTasks method in backendService.ts file, fulfils leading to the invocation of then(...) block in the calling code, i.e. in Entries.tsx file.

如果 axios.get(...) 返回的 Promise 被拒绝,catch(...) 块将执行.由于 getTasks 方法中的 catch(...) 块只是记录错误,getTasks 方法返回的 Promise满足undefined的值,这将导致调用代码中then(...)块的调用,即在 Entries.tsx 文件中.

If the Promise returned by axios.get(...) is rejected, catch(...) block will execute. Since catch(...) block in getTasks method is just logging the error, Promise returned by getTasks method will fulfil with the value of undefined which will lead to the invocation of then(...) block in the calling code, i.e. in Entries.tsx file.

请参阅以下示例以了解这一点.

See the following example to understand this.

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,因此从 then 中抛出错误 块被同一函数中的 catch 块捕获.由于这个 catch 块只是记录一条消息并返回 undefinedgetData 函数返回的 Promise 用值实现未定义.因此,不是 catch 块,then 块在调用 getData 函数的代码中执行.

In the above code snippet, as API URL is not correct, response.ok in the then block is false, so error is thrown from the then block which is caught by the catch block in the same function. As this catch block is just logging a message and returning undefined, Promise returned by getData function fulfils with the value of undefined. So instead of the catch block, then block executes in the code that calls getData function.

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

If you didn't know this then you might be surprised to see this behavior but that is how Promises work with catch blocks. The reason for this behavior is that if you have a promise chain that has more than one catch block, like shown below:

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

然后,如果第一个 catch 块捕获了从它之前链接的任何函数抛出的错误,则此 catch 块可以执行以下两项操作之一:

then if the first catch block catches an error that is thrown from any of the functions chained before it, then this catch block can do one of the following two things:

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

如果第一个 catch 块正常返回,则 catch 块返回的承诺与 catch 块的返回值和这个值一起履行then 成为promise 链中下一个then 块的回调函数的输入.所以承诺链继续而不是在第一个 catch 块执行后立即停止.

if the first catch block returns normally, the promise returned by catch block fulfills with that return value of the catch block and this value then becomes the input of the callback function of the next then block in the promise chain. So the promise chain continues instead of stopping as soon as first catch block executes.

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

Coming back to your code, when catch block executes in the getTasks method in backendService.ts file, it logs the message and returns undefined which then leads to the invocation of then block in the Entries.tsx file, instead of the catch block and that is why you get a complaint from typescript about your code.

解决方案

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

You can use one of the following options to solve this problem:

  • 抛出backendService.ts文件中getTasks方法的catch(...)块中捕获的错误,以便getTasks 方法返回的 Promise 被拒绝,而不是用 undefined 的值实现.

  • Throw the error caught in the catch(...) block of getTasks method in backendService.ts file so that Promise returned by getTasks method is rejected instead of fulfilling with the value of undefined.

删除backendService.ts文件中getTasks函数中的catch块并添加catch> 阻止调用 getTasks 方法的代码.

Remove the catch block in the getTasks function in backendService.ts file and add the catch block in the code that calls getTasks method.

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

In my opinion, there's no need for a catch block in the backendService.ts file because if the Promise returned by axios.get(...) is rejected, Promise returned by getTasks method will also be rejected if there's no catch block in the getTasks method. So just remove the catch(...) block from the getTasks method and add the catch(...) block where you are calling this getTasks method.

这篇关于处理 Typescript 中的 Promise 捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆