处理 Typescript 中的 Promise 捕获 [英] Handle Promise Catches in Typescript
问题描述
我有一个基于 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
块正在返回 undefined
和 catch
块返回一个值而不是抛出捕获的错误,而不是调用调用代码的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 byaxios.get(...)
fulfils then what you do in thethen(...)
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(...)
块将执行,因为它只返回 tasks
、Promise
由 backendService.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
块只是记录一条消息并返回 undefined
,getData
函数返回的 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.
如果您不知道这一点,那么您可能会惊讶地看到这种行为,但这就是 Promises
与 catch
块一起工作的方式.这种行为的原因是如果你有一个包含多个 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 ofgetTasks
method inbackendService.ts
file so thatPromise
returned bygetTasks
method is rejected instead of fulfilling with the value ofundefined
.
删除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
块,因为如果 返回的
被拒绝,如果没有 Promise
axios.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屋!