node.js 使用 async/await 尝试/捕获块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40884153/
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
try/catch blocks with async/await
提问by Patrick
I'm digging into the node 7 async/await feature and keep stumbling across code like this
我正在深入研究 node 7 async/await 功能,并在这样的代码中不断磕磕绊绊
function getQuote() {
let quote = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
return quote;
}
async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}
main();
This seems to be the only possibility resolve/reject or return/throw with async/await, however, v8 doesn't optimise code within try/catch blocks?!
这似乎是使用 async/await 解决/拒绝或返回/抛出的唯一可能性,但是,v8 没有优化 try/catch 块中的代码?!
Are there alternatives?
有替代品吗?
回答by rsp
Alternatives
备择方案
An alternative to this:
一个替代方案:
async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}
would be something like this, using promises explicitly:
将是这样的,明确使用承诺:
function main() {
getQuote().then((quote) => {
console.log(quote);
}).catch((error) => {
console.error(error);
});
}
or something like this, using continuation passing style:
或类似的东西,使用延续传递风格:
function main() {
getQuote((error, quote) => {
if (error) {
console.error(error);
} else {
console.log(quote);
}
});
}
Original example
原始示例
What your original code does is suspend the execution and wait for the promise returned by getQuote()to settle. It then continues the execution and writes the returned value to var quoteand then prints it if the promise was resolved, or throws an exception and runs the catch block that prints the error if the promise was rejected.
您的原始代码所做的是暂停执行并等待 返回的承诺getQuote()解决。然后它继续执行并将返回的值写入var quote并打印它,如果承诺已解决,或者抛出异常并运行 catch 块,如果承诺被拒绝,则打印错误。
You can do the same thing using the Promise API directly like in the second example.
您可以像在第二个示例中一样直接使用 Promise API 执行相同的操作。
Performance
表现
Now, for the performance. Let's test it!
现在,为了表演。让我们来测试一下!
I just wrote this code - f1()gives 1as a return value, f2()throws 1as an exception:
我刚才写的代码-f1()给1作为返回值,f2()抛出1一个例外:
function f1() {
return 1;
}
function f2() {
throw 1;
}
Now let's call the same code million times, first with f1():
现在让我们调用相同的代码百万次,首先是f1():
var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
console.log(sum);
And then let's change f1()to f2():
然后让我们f1()改为f2():
var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
console.log(sum);
This is the result I got for f1:
这是我得到的结果f1:
$ time node throw-test.js
1000000
real 0m0.073s
user 0m0.070s
sys 0m0.004s
This is what I got for f2:
这就是我得到的f2:
$ time node throw-test.js
1000000
real 0m0.632s
user 0m0.629s
sys 0m0.004s
It seems that you can do something like 2 million throws a second in one single-threaded process. If you're doing more than that then you may need to worry about it.
似乎您可以在一个单线程进程中每秒执行 200 万次抛出。如果你做得更多,那么你可能需要担心它。
Summary
概括
I wouldn't worry about things like that in Node. If things like that get used a lot then it will get optimized eventually by the V8 or SpiderMonkey or Chakra teams and everyone will follow - it's not like it's not optimized as a principle, it's just not a problem.
我不会担心 Node.js 中的类似事情。如果这样的东西被大量使用,那么它最终会被 V8 或 SpiderMonkey 或 Chakra 团队优化,每个人都会效仿——这并不是说它没有作为原则优化,这不是问题。
Even if it isn't optimized then I'd still argue that if you're maxing out your CPU in Node then you should probably write your number crunching in C - that's what the native addons are for, among other things. Or maybe things like node.nativewould be better suited for the job than Node.js.
即使它没有优化,那么我仍然认为,如果你在 Node 中最大化你的 CPU,那么你可能应该用 C 编写你的数字运算 - 这就是本机插件的用途等等。或者像node.native这样的东西可能比 Node.js 更适合这项工作。
I'm wondering what would be a use case that needs throwing so many exceptions. Usually throwing an exception instead of returning a value is, well, an exception.
我想知道需要抛出这么多异常的用例是什么。通常抛出异常而不是返回值是异常。
回答by Pulkit chadha
An alternative to try-catch block is await-to-jslib. I often use it. For example:
try-catch 块的替代方法是await-to-jslib。我经常使用它。例如:
import to from 'await-to-js';
async function main(callback) {
const [err,quote] = await to(getQuote());
if(err || !quote) return callback(new Error('No Quote found');
callback(null,quote);
}
This syntax is much cleaner when compared to try-catch.
与 try-catch 相比,这种语法要简洁得多。
回答by Steve Banton
Alternative Similar To Error Handling In Golang
替代类似于 Golang 中的错误处理
Because async/await uses promises under the hood, you can write a little utility function like this:
因为 async/await 在幕后使用了 promises,你可以写一个像这样的小工具函数:
export function catchEm(promise) {
return promise.then(data => [null, data])
.catch(err => [err]);
}
Then import it whenever you need to catch some errors, and wrap your async function which returns a promise with it.
然后在您需要捕获一些错误时导入它,并包装您的异步函数,该函数用它返回一个承诺。
import catchEm from 'utility';
async performAsyncWork() {
const [err, data] = await catchEm(asyncFunction(arg1, arg2));
if (err) {
// handle errors
} else {
// use data
}
}
回答by Tony
async function main() {
var getQuoteError
var quote = await getQuote().catch(err => { getQuoteError = err }
if (getQuoteError) return console.error(err)
console.log(quote)
}
Alternatively instead of declaring a possible var to hold an error at the top you can do
或者,您可以做的不是声明一个可能的 var 来在顶部保存错误
if (quote instanceof Error) {
// ...
}
Though that won't work if something like a TypeError or Reference error is thrown. You can ensure it is a regular error though with
尽管如果抛出 TypeError 或 Reference 错误之类的东西,那将不起作用。您可以确保这是一个常规错误
async function main() {
var quote = await getQuote().catch(err => {
console.error(err)
return new Error('Error getting quote')
})
if (quote instanceOf Error) return quote // get out of here or do whatever
console.log(quote)
}
My preference for this is wrapping everything in a big try-catch block where there's multiple promises being created can make it cumbersome to handle the error specifically to the promise that created it. With the alternative being multiple try-catch blocks which I find equally cumbersome
我对此的偏好是将所有内容都包装在一个大的 try-catch 块中,其中创建了多个 Promise 可能会使专门针对创建它的 Promise 处理错误变得很麻烦。另一种方法是多个 try-catch 块,我发现它们同样麻烦
回答by zardilior
A cleaner alternative would be the following:
更清洁的替代方案如下:
Due to the fact that every async function is technically a promise
由于每个异步函数在技术上都是一个承诺
You can add catches to functions when calling them with await
您可以在使用 await 调用函数时向函数添加捕获
async function a(){
let error;
// log the error on the parent
await b().catch((err)=>console.log('b.failed'))
// change an error variable
await c().catch((err)=>{error=true; console.log(err)})
// return whatever you want
return error ? d() : null;
}
a().catch(()=>console.log('main program failed'))
No need for try catch, as all promises errors are handled, and you have no code errors, you can omit that in the parent!!
不需要try catch,因为所有的promise错误都被处理了,而且你没有代码错误,你可以在父级中省略它!!
Lets say you are working with mongodb, if there is an error you might prefer to handle it in the function calling it than making wrappers, or using try catches.
假设您正在使用 mongodb,如果出现错误,您可能更愿意在调用它的函数中处理它,而不是制作包装器或使用 try 捕获。
回答by Cooper Hsiung
I'd like to do this way :)
我想这样做:)
const sthError = () => Promise.reject('sth error');
const test = opts => {
return (async () => {
// do sth
await sthError();
return 'ok';
})().catch(err => {
console.error(err); // error will be catched there
});
};
test().then(ret => {
console.log(ret);
});
It's similar to handling error with co
它类似于处理错误 co
const test = opts => {
return co(function*() {
// do sth
yield sthError();
return 'ok';
}).catch(err => {
console.error(err);
});
};
回答by sarink
catching in this fashion, in my experience, is dangerous. Any error thrown in the entire stack will be caught, not just an error from this promise (which is probably not what you want).
catch以我的经验,这种方式是危险的。整个堆栈中抛出的任何错误都将被捕获,而不仅仅是此承诺的错误(这可能不是您想要的)。
The second argument to a promise is already a rejection/failure callback. It's better and safer to use that instead.
承诺的第二个参数已经是一个拒绝/失败回调。使用它更好更安全。
Here's a typescript typesafe one-liner I wrote to handle this:
这是我为处理此问题而编写的打字稿类型安全单行:
function wait<R, E>(promise: Promise<R>): [R | null, E | null] {
return (promise.then((data: R) => [data, null], (err: E) => [null, err]) as any) as [R, E];
}
// Usage
const [currUser, currUserError] = await wait<GetCurrentUser_user, GetCurrentUser_errors>(
apiClient.getCurrentUser()
);

