如何拒绝异步/等待功能返回的承诺?
例如本来
foo(id: string): Promise<A> {
return new Promise((resolve, reject) => {
someAsyncPromise().then((value)=>resolve(200)).catch((err)=>reject(400))
});
}
转换为异步/等待
async foo(id: string): Promise<A> {
try{
await someAsyncPromise();
return 200;
} catch(error) {//here goes if someAsyncPromise() rejected}
return 400; //this will result in a resolved promise.
});
}
那么,在这种情况下,我如何才能正确拒绝这一承诺?
最好的办法是到throw
一个Error
包装的价值,其结果与一个被拒绝的承诺,Error
包装的价值:
} catch (error) {
throw new Error(400);
}
您也可以只throw
输入值,但是没有堆栈跟踪信息:
} catch (error) {
throw 400;
}
或者,返回带有Error
包装值的被拒绝的promise ,但这不是惯用的:
} catch (error) {
return Promise.reject(new Error(400));
}
(或者只是return Promise.reject(400);
,但是再没有上下文信息。)
(在您的情况下,当您使用TypeScript
且foo
retrn值为时Promise<A>
,您将使用return Promise.reject<A>(400 /*or error*/);
)
在async
/await
情况下,最后一个可能有点语义上的不匹配,但它确实起作用。
如果抛出Error
,则可以很好地与foo
使用以下await
语法的结果一起使用:
try {
await foo();
} catch (error) {
// Here, `error` would be an `Error` (with stack trace, etc.).
// Whereas if you used `throw 400`, it would just be `400`.
}
可能还应该提到,您可以catch()
在调用异步操作之后简单地链接一个函数,因为在幕后仍然返回了一个Promise。
await foo().catch(error => console.log(error));
这样,您可以避免try/catch
不喜欢的语法。
您可以创建一个包装函数,该函数接受一个promise,如果没有错误,则返回一个包含数据的数组,如果有错误,则返回错误。
function safePromise(promise) {
return promise.then(data => [ data ]).catch(error => [ null, error ]);
}
在ES7和异步函数中像这样使用它:
async function checkItem() {
const [ item, error ] = await safePromise(getItem(id));
if (error) { return null; } // handle error and return
return item; // no error so safe to use item
}
编写异步函数的更好方法是从头开始返回待处理的Promise,然后在Promise的回调中处理拒绝和解决方案,而不是随便吐出错误时被拒绝的Promise。例:
async foo(id: string): Promise<A> {
return new Promise(function(resolve, reject) {
// execute some code here
if (success) { // let's say this is a boolean value from line above
return resolve(success);
} else {
return reject(error); // this can be anything, preferably an Error object to catch the stacktrace from this function
}
});
}
然后,您只需在返回的Promise上链接方法:
async function bar () {
try {
var result = await foo("someID")
// use the result here
} catch (error) {
// handle error here
}
}
bar()
来源-本教程:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
我建议以一种新颖的方法正确处理不合格品,而不必使用多个try-catch块。
import to from './to';
async foo(id: string): Promise<A> {
let err, result;
[err, result] = await to(someAsyncPromise()); // notice the to() here
if (err) {
return 400;
}
return 200;
}
凡to.ts功能应该从进口:
export default function to(promise: Promise<any>): Promise<any> {
return promise.then(data => {
return [null, data];
}).catch(err => [err]);
}
在以下链接中将版权归Dima Grossman所有。
这不是@TJ Crowder的答案。只是对评论作出回应的评论“而且,实际上,如果将异常转换为拒绝,则我不确定如果是错误,是否真的被打扰了。我抛出仅错误的原因可能并不适用。 ”
如果您的代码使用async
/ await
,则最好使用Error
而不是拒绝400
:
try {
await foo('a');
}
catch (e) {
// you would still want `e` to be an `Error` instead of `400`
}
我知道这是一个古老的问题,但是我偶然发现了该线程,并且错误和拒绝之间似乎存在混淆,这与经常重复使用的建议(至少在许多情况下)不使用异常处理处理预期的案件。举例说明:如果异步方法正在尝试对用户进行身份验证而身份验证失败,则表示拒绝(两种预期情况之一),而不是错误(例如,如果身份验证API不可用)。
为了确保我不仅仅是在分裂头发,我使用以下代码对三种不同的方法进行了性能测试:
const iterations = 100000;
function getSwitch() {
return Math.round(Math.random()) === 1;
}
function doSomething(value) {
return 'something done to ' + value.toString();
}
let processWithThrow = function () {
if (getSwitch()) {
throw new Error('foo');
}
};
let processWithReturn = function () {
if (getSwitch()) {
return new Error('bar');
} else {
return {}
}
};
let processWithCustomObject = function () {
if (getSwitch()) {
return {type: 'rejection', message: 'quux'};
} else {
return {type: 'usable response', value: 'fnord'};
}
};
function testTryCatch(limit) {
for (let i = 0; i < limit; i++) {
try {
processWithThrow();
} catch (e) {
const dummyValue = doSomething(e);
}
}
}
function testReturnError(limit) {
for (let i = 0; i < limit; i++) {
const returnValue = processWithReturn();
if (returnValue instanceof Error) {
const dummyValue = doSomething(returnValue);
}
}
}
function testCustomObject(limit) {
for (let i = 0; i < limit; i++) {
const returnValue = processWithCustomObject();
if (returnValue.type === 'rejection') {
const dummyValue = doSomething(returnValue);
}
}
}
let start, end;
start = new Date();
testTryCatch(iterations);
end = new Date();
const interval_1 = end - start;
start = new Date();
testReturnError(iterations);
end = new Date();
const interval_2 = end - start;
start = new Date();
testCustomObject(iterations);
end = new Date();
const interval_3 = end - start;
console.log(`with try/catch: ${interval_1}ms; with returned Error: ${interval_2}ms; with custom object: ${interval_3}ms`);
由于我对Javascript解释器的不确定性,其中包含了其中的一些内容(我只喜欢一次钻一个兔子洞)。例如,我包含了该doSomething
函数并为其分配了返回值,dummyValue
以确保不会对条件块进行优化。
我的结果是:
with try/catch: 507ms; with returned Error: 260ms; with custom object: 5ms
我知道在很多情况下寻找小小的优化是不值得的,但是在大型系统中,这些事情会产生很大的累加差异,这是一个非常鲜明的比较。
如此…虽然我认为在您期望必须处理异步功能内不可预测的错误的情况下,可以接受的答案的方法是合理的,但在拒绝仅意味着“您将必须使用计划B(或C或D…)“,我想我的首选是拒绝使用自定义响应对象。
文章标签:asynchronous , ecmascript-2017 , es6-promise , javascript , typescript
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!