비동기/동기화된 블록 시도/동기화
노드 7 7을 . 를파있습다니고드노번다▁7▁i있니습▁node.async
/await
와 같은 를 특징짓고 .
function getQuote() {
let quote = "Lorem ipsum dolor sit amet, consectetur adipiscing elit laborum.";
return quote;
}
async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}
main();
한 가능성인 것 .resolve
/reject
또는return
/throw
와 함께async
/await
그러나 v8은 내부 코드를 최적화하지 않습니다.try
/catch
블록?!
대안이 있습니까?
대안
이에 대한 대안:
async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}
약속을 명시적으로 사용하는 것은 다음과 같습니다.
function main() {
getQuote().then((quote) => {
console.log(quote);
}).catch((error) => {
console.error(error);
});
}
또는 연속 전달 스타일을 사용하여 다음과 같은 작업을 수행합니다.
function main() {
getQuote((error, quote) => {
if (error) {
console.error(error);
} else {
console.log(quote);
}
});
}
원본 예제
의 원래 일은 하고 원래코수는작행업하은실일행다을중것에 의해 된 입니다.getQuote()
그리고 하고 반환된 을 그런다실계반값다씁음을니에다환된고에 씁니다.var quote
그런 다음 약속이 해결된 경우 이를 인쇄하거나, 예외를 던지고 약속이 거부된 경우 오류를 인쇄하는 캐치 블록을 실행합니다.
두 번째 예제처럼 Promise API를 직접 사용하여 동일한 작업을 수행할 수 있습니다.
성능
이제 퍼포먼스를 위해서.시험해 보겠습니다!
이 - 방금이코작성니다습했를드다▁-니.f1()
, 주다, 주다, 주다, 주다, 주다, 주다, 주다, 주다, 주다.1
반환값으로,,f2()
1
예외적으로:
function f1() {
return 1;
}
function f2() {
throw 1;
}
같은 번 불러보도록 f1()
:
var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
console.log(sum);
그리고 옷을 갈아입자꾸나f1()
f2()
:
var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
console.log(sum);
이것이 제가 얻은 결과입니다.f1
:
$ time node throw-test.js
1000000
real 0m0.073s
user 0m0.070s
sys 0m0.004s
이것이 제가 받은 것입니다.f2
:
$ time node throw-test.js
1000000
real 0m0.632s
user 0m0.629s
sys 0m0.004s
한 번의 스레드 과정에서 2백만 개의 초를 던질 수 있는 것처럼 보입니다.만약 당신이 그 이상을 하고 있다면 당신은 그것에 대해 걱정할 필요가 있을 것입니다.
요약
나는 노드에서 그런 것들에 대해 걱정하지 않을 것입니다.그런 것들이 많이 사용되면 결국 V8, 스파이더몽키 또는 차크라 팀에 의해 최적화되고 모든 사람들이 따를 것입니다. 원칙적으로 최적화되지 않은 것이 아니라 문제가 되지 않습니다.
최적화되지 않았다고 해도 노드에서 CPU를 최대로 사용하고 있다면 아마도 C로 숫자를 입력해야 한다고 주장합니다. 이것이 바로 네이티브 추가 기능이 무엇보다도 중요한 이유입니다.또는 Node.js보다 node.native와 같은 것이 작업에 더 적합할 수 있습니다.
이렇게 많은 예외를 두어야 하는 사용 사례가 무엇인지 궁금합니다.일반적으로 값을 반환하는 대신 예외를 던지는 것은 예외입니다.
Golang의 오류 처리와 유사한 대안
비동기/대기는 후드 아래에서 약속을 사용하기 때문에 다음과 같은 작은 유틸리티 함수를 작성할 수 있습니다.
export function catchEm(promise) {
return promise.then(data => [null, data])
.catch(err => [err]);
}
그런 다음 오류를 발견해야 할 때마다 가져오기를 하고 약속을 반환하는 비동기 함수를 래핑합니다.
import catchEm from 'utility';
async performAsyncWork() {
const [err, data] = await catchEm(asyncFunction(arg1, arg2));
if (err) {
// handle errors
} else {
// use data
}
}
try-catch 블록의 대안은 wait-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);
}
이 구문은 try-catch와 비교했을 때 훨씬 깨끗합니다.
async function main() {
var getQuoteError
var quote = await getQuote().catch(err => { getQuoteError = err }
if (getQuoteError) return console.error(err)
console.log(quote)
}
또는 가능한 변수를 선언하여 맨 위에 오류를 보류하는 대신 할 수 있습니다.
if (quote instanceof Error) {
// ...
}
유형 오류 또는 참조 오류와 같은 오류가 발생하면 작동하지 않습니다.하지만 정기적인 오류임을 확인할 수 있습니다.
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)
}
제가 선호하는 것은 여러 개의 약속이 생성되는 큰 트라이캐치 블록으로 모든 것을 포장하는 것입니다. 특히 오류를 생성한 약속에 대해 처리하는 것이 번거로울 수 있습니다.여러 개의 트라이캐치 블록을 사용하는 것도 마찬가지로 번거롭습니다.
더 깨끗한 대안은 다음과 같습니다.
모든 비동기 함수는 기술적으로 약속이기 때문에
wait와 함께 호출할 때 함수에 캐치를 추가할 수 있습니다.
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'))
모든 약속 오류가 처리되고 코드 오류가 없으므로 시도 캐치가 필요 없습니다. 부모에서 생략할 수 있습니다!
만약 당신이 mongodb로 작업하고 있다면, 만약 오류가 있다면, 당신은 그것을 호출하는 함수에서 그것을 처리하는 것이 래퍼를 만들거나 시도 캐치를 사용하는 것보다 더 나을 수 있습니다.
MDN DOCS의 약속을 어떻게 사용할 것인가에 대한 간단하고 잘 설명된 예가 있다고 생각합니다.
예를 들어, 그들은 API Fetch와 두 가지 유형을 사용합니다. 하나는 일반 유형이고 다른 하나는 비동기와 Promise가 함께 혼합된 하이브리드입니다.
- 간단한 예
async function myFetch() {
let response = await fetch("coffee.jpg");
// Added manually a validation and throws an error
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let myBlob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement("img");
image.src = objectURL;
document.body.appendChild(image);
}
myFetch().catch((e) => {
// Catches the errors...
console.log("There has been a problem with your fetch operation: " + e.message);
});
- 하이브리드 접근법
비동기 키워드는 함수를 약속으로 전환하므로, 약속과 대기의 하이브리드 접근 방식을 사용하도록 코드를 재팩터링할 수 있으며, 함수의 후반부를 새로운 블록으로 가져와서 더 유연하게 만들 수 있습니다.
async function myFetch() {
// Uses async
let response = await fetch("coffee.jpg");
// Added manually a validation and throws an error
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.blob();
}
myFetch()
.then((blob) => {
// uses plain promise
let objectURL = URL.createObjectURL(blob);
let image = document.createElement("img");
image.src = objectURL;
document.body.appendChild(image);
})
.catch((e) => console.log(e));
오류 처리 추가
- 보통의
async function myFetch() {
try {
let response = await fetch("coffee.jpg");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let myBlob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement("img");
image.src = objectURL;
document.body.appendChild(image);
} catch (e) {
console.log(e);
}
}
myFetch();
- 하이브리드(최적)
async function myFetch() {
let response = await fetch("coffee.jpg");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.blob();
}
myFetch()
.then((blob) => {
let objectURL = URL.createObjectURL(blob);
let image = document.createElement("img");
image.src = objectURL;
document.body.appendChild(image);
})
.catch(
(
e // Not need a try catch. This will catch it all already!
) => console.log(e)
);
최선의 해결책
이러한 원칙을 따르지만 더 명확하게 하는 가장 좋은 해결책은 이 대답입니다. --> StackOverflow: 비동기/대기로 블록을 시도/캐치합니다.여기서
function promiseHandle(promise) {
return promise.then((data) => [null, data]).catch((err) => [err]);
}
async function asyncFunc(param1, param2) {
const [err, data] = await promiseHandle(expensiveFunction(param1, param2));
// This just to show, that in this way we can control what is going on..
if (err || !data) {
if (err) return Promise.reject(`Error but not data..`);
return Promise.reject(`Error but not data..`);
}
return Promise.resolve(data);
}
저는 이 방법으로 하고 싶습니다 :)
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);
});
오류를 처리하는 것과 유사합니다.co
const test = opts => {
return co(function*() {
// do sth
yield sthError();
return 'ok';
}).catch(err => {
console.error(err);
});
};
wait-to-js와 같은 라이브러리가 필요하지 않습니다, 간단한 한 줄기.to
- 기능(다른 답변에도 표시됨)은 다음을 수행합니다.
const to = promise => promise.then(res => [null, res]).catch(err => [err || true, null]);
용도:
async function main()
{
var [err, quote] = await to(getQuote());
if(err)
{
console.log('warn: Could not get quote.');
}
else
{
console.log(quote);
}
}
그러나 오류로 인해 다음과 같은 기능 또는 프로그램이 종료되는 경우:
async function main()
{
var [err, quote] = await to(getQuote());
if(err) return console.error(err);
console.log(quote);
}
그런 다음 main()에서 오류가 자동으로 반환되도록 하는 것이 좋습니다. main()은 예외의 의도된 목적입니다.
async function main()
{
var quote = await getQuote();
console.log(quote);
}
main().catch(err => console.error('error in main():', err));
오류 던지기 vs 오류 반환
발생할 것으로 예상되는 오류를 처리할 것으로 예상되는 경우 다음을 사용합니다.throw
또는reject
나쁜 관행입니다.그 대신에,getQuote()
함수는 항상 다음 중 하나를 사용하여 확인합니다.
resolve([err, result])
resolve(null)
resolve(new Error(...))
resolve({error: new Error(), result: null})
- 기타.
오류를 던지는 것(또는 비동기: 약속을 거부하는 것)은 예외로 남아 있어야 합니다.예외는 상황이 악화될 때만 발생하고 정상적인 사용 중에는 발생해서는 안 되므로 최적화가 우선 순위가 아닙니다.따라서 예외의 유일한 결과는 함수의 종료일 수 있으며, 이는 어쨌든 탐지되지 않은 경우 기본 동작입니다.
잘못 설계된 타사 라이브러리를 다루거나 의도하지 않은 사용 사례를 위해 타사 라이브러리 기능을 사용하는 경우가 아니라면 아마도to
-기능.
catch
이런 식으로 말하는 것은, 제 경험상, 위험합니다.이 약속(아마도 원하는 것이 아닐 것)의 오류뿐만 아니라 전체 스택에 발생한 모든 오류가 탐지됩니다.
약속의 두 번째 인수는 이미 거부/실패 콜백입니다.대신 그것을 사용하는 것이 더 낫고 안전합니다.
다음은 제가 이 문제를 해결하기 위해 작성한 타이프스크립트 형식의 세이프 원라이너입니다.
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()
);
Express 프레임워크의 경우, 저는 일반적으로 다음과 같은 방법을 따릅니다.우리는 약속을 해결하는 기능을 만들 수 있습니다.예를 들면catchAsync
함수:
const catchAsync = (fn) => (req, res, next) =>{
Promise.resolve(fn(req, res, next)).catch((err) => next(err));
});
이 기능은 시도/캐치가 필요한 곳이면 어디든 호출할 수 있습니다.이 기능은 우리가 호출하는 기능을 수용하고 수행되는 동작을 기반으로 이를 해결하거나 거부합니다.이렇게 부를 수 있습니다.
const sampleFunction = catchAsync(async (req, res) => {
const awaitedResponse = await getResponse();
res.send(awaitedResponse);
});
언급URL : https://stackoverflow.com/questions/40884153/try-catch-blocks-with-async-await
'sourcecode' 카테고리의 다른 글
postgresql의 문자열 리터럴 및 이스케이프 문자 (0) | 2023.05.29 |
---|---|
git 특정 커밋으로 되돌리기 (0) | 2023.05.29 |
COM 예외 클래스가 등록되지 않은 문제를 해결하는 방법(HRESULT: 0x80040154(REGDB_E_CLASSNOTREG)의 예외)? (0) | 2023.05.29 |
mongoengine - 스키마 유효성 검사를 위해 추가 필드를 무시 (0) | 2023.05.29 |
치명적 오류: 잘못된 형식 또는 손상된 AST 파일 - Xcode (0) | 2023.05.29 |