Javascript 如何在 async/await 语法中拒绝?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42453683/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to reject in async/await syntax?
提问by Phoenix
How can I reject a promise that returned by an async/await function?
如何拒绝 async/await 函数返回的承诺?
e.g. Originally
例如原来
foo(id: string): Promise<A> {
return new Promise((resolve, reject) => {
someAsyncPromise().then((value)=>resolve(200)).catch((err)=>reject(400))
});
}
Translate into async/await
转换为 async/await
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.
});
}
So, how could I properly reject this promise in this case?
那么,在这种情况下,我怎么能正确拒绝这个承诺呢?
回答by T.J. Crowder
Your best bet is to throwan Errorwrapping the value, which results in a rejected promise with an Errorwrapping the value:
你最好的选择是包装价值,这会导致throw一个Error包装价值的被拒绝的承诺Error:
} catch (error) {
throw new Error(400);
}
You can also just throwthe value, but then there's no stack trace information:
您也可以只throw使用值,但是没有堆栈跟踪信息:
} catch (error) {
throw 400;
}
Alternately, return a rejected promise with an Errorwrapping the value, but it's not idiomatic:
或者,返回一个被拒绝的承诺并Error包装价值,但这不是惯用的:
} catch (error) {
return Promise.reject(new Error(400));
}
(Or just return Promise.reject(400);, but again, then there's no context information.)
(或者只是return Promise.reject(400);,但同样,则没有上下文信息。)
(In your case, as you're using TypeScriptand foo's retrn value is Promise<A>, you'd use return Promise.reject<A>(400 /*or error*/);)
(在您的情况下,当您使用TypeScript和foo的 retrn 值时Promise<A>,您会使用return Promise.reject<A>(400 /*or error*/);)
In an async/awaitsituation, that last is probably a bit of a semantic mis-match, but it does work.
在async/ 的await情况下,最后一个可能有点语义不匹配,但它确实有效。
If you throw an Error, that plays well with anything consuming your foo's result with awaitsyntax:
如果你抛出一个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`.
}
回答by David
It should probably also be mentioned that you can simply chain a catch()function after the call of your async operation because under the hood still a promise is returned.
可能还应该提到的是,您可以catch()在调用异步操作之后简单地链接一个函数,因为在幕后仍然会返回一个 promise。
await foo().catch(error => console.log(error));
This way you can avoid the try/catchsyntax if you do not like it.
try/catch如果你不喜欢它,你可以通过这种方式避免语法。
回答by Andy
You can create a wrapper functionthat takes in a promiseand returns an array with data if no error and the error if there was an error.
您可以创建一个包装函数,它接受一个承诺并返回一个数组,如果没有错误,则返回一个包含数据的数组,如果有错误,则返回错误。
function safePromise(promise) {
return promise.then(data => [ data ]).catch(error => [ null, error ]);
}
Use it like this in ES7and in an asyncfunction:
在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
}
回答by OzzyTheGiant
A better way to write the async function would be by returning a pending Promise from the start and then handling both rejections and resolutions within the callback of the promise, rather than just spitting out a rejected promise on error. Example:
编写异步函数的更好方法是从一开始就返回一个挂起的 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
}
});
}
Then you just chain methods on the returned promise:
然后你只需在返回的承诺上链接方法:
async function bar () {
try {
var result = await foo("someID")
// use the result here
} catch (error) {
// handle error here
}
}
bar()
Source - this tutorial:
来源 - 本教程:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
回答by Pedro Louren?o
I have a suggestion to properly handle rejectsin a novel approach, without having multiple try-catch blocks.
我有一个建议,以一种新颖的方法正确处理拒绝,而无需多个 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;
}
Where the to.tsfunction should be imported from:
应从何处导入to.ts函数:
export default function to(promise: Promise<any>): Promise<any> {
return promise.then(data => {
return [null, data];
}).catch(err => [err]);
}
Credits go to Dima Grossman in the following link.
学分转到以下链接中的 Dima Grossman 。
回答by RiqueW
I know this is an old question, but I just stumbled across the thread and there seems to be a conflation here between errors and rejection that runs afoul (in many cases, at least) of the oft-repeated advice not to use exception handling to deal with anticipated cases. To illustrate: if an async method is trying to authenticate a user and the authentication fails, that's a rejection (one of two anticipated cases) and not an error (e.g., if the authentication API was unavailable.)
我知道这是一个老问题,但我只是偶然发现了该线程,错误和拒绝之间似乎存在混淆,这与经常重复的建议不使用异常处理(至少在许多情况下)发生冲突处理预期的案件。举例说明:如果异步方法尝试对用户进行身份验证并且身份验证失败,则这是拒绝(两种预期情况之一)而不是错误(例如,如果身份验证 API 不可用。)
To make sure I wasn't just splitting hairs, I ran a performance test of three different approaches to that, using this code:
为确保我不只是分心,我使用以下代码对三种不同的方法进行了性能测试:
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`);
Some of the stuff that's in there is included because of my uncertainty regarding the Javascript interpreter (I only like to go down one rabbit hole at a time); for instance, I included the doSomethingfunction and assigned its return to dummyValueto ensure that the conditional blocks wouldn't get optimized out.
由于我对 Javascript 解释器的不确定性(我一次只喜欢进入一个兔子洞),因此包含了其中的一些内容;例如,我包含了该doSomething函数并将其返回分配给以dummyValue确保条件块不会被优化掉。
My results were:
我的结果是:
with try/catch: 507ms; with returned Error: 260ms; with custom object: 5ms
I know that there are plenty of cases where it's not worth the trouble to hunt down small optimizations, but in larger-scale systems these things can make a big cumulative difference, and that's a pretty stark comparison.
我知道在很多情况下不值得费心去寻找小的优化,但在大规模系统中,这些事情可以产生很大的累积差异,这是一个非常明显的比较。
SO… while I think the accepted answer's approach is sound in cases where you're expecting to have to handle unpredictable errors within an async function, in cases where a rejection simply means "you're going to have to go with Plan B (or C, or D…)" I think my preference would be to reject using a custom response object.
所以......虽然我认为在您期望必须在异步函数中处理不可预测的错误的情况下,接受的答案的方法是合理的,但在拒绝仅意味着“您将不得不采用计划 B(或C 或 D...)” 我认为我的偏好是拒绝使用自定义响应对象。
回答by unional
This is not an answer over @T.J. Crowder's one. Just an comment responding to the comment "And actually, if the exception is going to be converted to a rejection, I'm not sure whether I am actually bothered if it's an Error. My reasons for throwing only Error probably don't apply."
这不是对@TJ Crowder 的回答。只是对评论的评论“实际上,如果异常将被转换为拒绝,我不确定我是否真的为它感到困扰,如果它是一个错误。我只抛出错误的原因可能不适用。 ”
if your code is using async/await, then it is still a good practice to reject with an Errorinstead of 400:
如果您的代码正在使用async/ await,那么使用Error代替来拒绝仍然是一个好习惯400:
try {
await foo('a');
}
catch (e) {
// you would still want `e` to be an `Error` instead of `400`
}

