JavaScript에서 비동기 대기 오류 처리
본문
async/await에서의 오류 처리는 많은 혼란을 야기합니다. 비동기 함수에서 오류를 처리하는 데는 여러 가지 패턴이 있으며 숙련된 개발자조차도 때때로 오류가 발생합니다.
비동기 함수 run()이 있다고 가정하십시오. 이 기사에서는 run()에서 오류를 처리하기 위한 3 가지 패턴 (try / catch, Golang-style 및 catch())을 함수 호출에서 설명합니다. 또한 비동기 함수를 사용하여 catch() 이외의 것을 거의 필요로 하지 않는 이유에 대해서도 설명합니다.
http://thecodebarbarian.com/async-await-error-handling-in-javascript.html
try/catch
async / await를 처음 시작하면 모든 비동기 작업 주위에 try / catch를 사용하고 싶은 유혹이 있습니다. 거부하는 promise을 await하면 JavaScript에서 잡을 수 있는 오류가 발생하기 때문입니다.
run();
async function run() {
try {
await Promise.reject(new Error('Oops!'));
} catch (error) {
error.message; // "Oops!"
}
}
try / catch는 동기 오류도 처리합니다.
run();
async function run() {
const v = null;
try {
await Promise.resolve('foo');
v.thisWillThrow;
} catch (error) {
// "TypeError: Cannot read property 'thisWillThrow' of null"
error.message;
}
}
그래서 당신이 해야 할 일은 모든 논리를 try / catch로 감싸는 것입니다. 좀 빠지는. 아래 코드는 처리되지 않은 약속 거부로 이어집니다. await 키워드는 약속 거부를 catchable 오류로 변환하지만 return은 그렇지 않습니다.
run();
async function run() {
try {
// Note that this is a `return`, not `await`
return Promise.reject(new Error('Oops!'));
} catch (error) {
// Will **not** run
}
}
return await를 사용하여 이 제한을 해결할 수 있습니다. 그러나 return await를 잊어 버리기 쉽습니다.
다른 단점은 try / catch가 작성하기 어렵다는 것입니다. try / catch가 동기화 및 비동기 오류를 처리한다는 것을 알고 나면 아래에 표시된 것처럼 모든 async 논리를 한 번의 try/catch로 래핑하고 싶은 유혹이 있습니다.
Golang in JS
또 다른 일반적인 패턴은 .then()을 사용하여 거부 된 promise을 오류가 있는 promise으로 변환하는 것입니다. 그런 다음 Golang과 같이 if(err) 검사를 사용할 수 있습니다.
run();
async function throwAnError() {
throw new Error('Oops!');
}
async function noError() {
return 42;
}
async function run() {
// The `.then(() => null, err => err)` pattern gives you an
// error if one occurred, or `null` otherwise
let err = await throwAnError().then(() => null, err => err);
if (err != null) {
err.message; // 'Oops'
}
err = await noError().then(() => null, err => err);
err; // null
}
오류와 값이 모두 필요한 경우 실제로 JavaScript로 Golang을 작성하는 것처럼 가장 할 수 있습니다.
run();
async function throwAnError() {
throw new Error('Oops!');
}
async function noError() {
return 42;
}
async function run() {
// The `.then(v => [null, v], err => [err, null])` pattern
// lets you use array destructuring to get both the error and
// the result
let [err, res] = await throwAnError().
then(v => [null, v], err => [err, null]);
if (err != null) {
err.message; // 'Oops'
}
err = await noError().
then(v => [null, v], err => [err, null]);
err; // null
res; // 42
}
try 블록에서 변수를 선언하여 변수를 try 블록으로 범위를 지정하기 때문에 이 패턴은 구문 적으로 깔끔 할 수 있습니다.
const getAnswer = async () => 42;
run();
async function run() {
try {
let val = await getAnswer();
} catch (error) {}
// ReferenceError: val is not defined
val;
}
Golang 스타일 오류 처리는 반환 문제를 제거하지 않습니다. 비동기 작업 후 if (err! = null)이 없으면 무언가 잘못되었음을 알기 때문에 누락 된 오류 검사를 더 어렵게 만듭니다.
Golang 스타일 오류 처리에는 두 가지 주요 단점이 있습니다.
- 매우 반복적입니다. 비동기식으로 할 때마다 if (err! = null)를 입력하면 손목 터널로 가는 급행 차선으로 연결됩니다.
- run()의 동기 오류에 도움이 되지 않습니다.
따라서 Golang 스타일의 오류 처리는 깔끔한 구문 단축키로 드물게 사용해야 합니다. try / catch를 사용하는 것보다 많은 이점이 없습니다.
함수 호출에서 catch() 사용
try/catch 및 Golang 스타일 오류 처리는 모두 용도가 있지만 run() 함수의 모든 오류를 처리하는 가장 좋은 방법은 run(). catch()를 사용하는 것입니다. 즉, 각 개별 오류를 처리하는 대신 함수를 호출 할 때 오류를 처리하십시오.
run().
catch(function handleError(err) {
err.message; // Oops!
}).
// Handle any errors in `handleError()`. If the error handler
// throws an error, kill the process.
catch(err => { process.nextTick(() => { throw err; }) });
async function run() {
await Promise.reject(new Error('Oops!'));
}
비동기 함수는 항상 약속을 반환합니다. 이 약속은 함수에서 포착되지 않은 오류가 발생하면 거부합니다. 비동기 함수 본문이 거부하는 약속을 반환하면 반환 된 약속도 거부됩니다.
run().
catch(function handleError(err) {
err.message; // Oops!
}).
// Handle any errors in `handleError()`. If the error handler
// throws an error, kill the process.
catch(err => { process.nextTick(() => { throw err; }) });
async function run() {
// Note that this is `return`, not `await`
return Promise.reject(new Error('Oops!'));
}
try/catch에 전체 run() 함수 본문을 래핑하는 것과 달리 run(). catch()가 필요한 이유는 무엇입니까? 오류 처리기에서 오류를 처리합니다. try/catch의 catch 블록에 오류가 발생하면 어떻게 됩니까? 유일한 해결책은 모든 단일 함수에서 catch 블록에 try/catch를 중첩시키는 것입니다. .catch()는 오류 처리기 클리너에서 예기치 않은 오류를 처리합니다.
Takeaways
일반적으로 오류는 예상되거나 예상치 못한 오류입니다. 비동기 함수에서 try/catch를 사용하면 예상되는 오류를 정상적으로 복구 할 수 있습니다. 그러나 예기치 않은 오류가 발생하면 때때로 "TypeError : null 속성 'foo'속성을 읽을 수 없습니다"라는 놀라운 결과가 발생합니다.
호출 함수의 비동기 함수에서 예기치 않은 오류를 처리해야 합니다. run() 함수는 모든 가능한 오류를 처리하는 책임을 지지 않아야 하며 대신 run().catch (handleError)를 수행해야 합니다.
- 이전글WebSockets 튜토리얼 : Node and React로 실시간으로 이동하는 방법(1) 19.08.07
- 다음글비동기(async) JS에 대한 시각적 학습자 안내서 19.08.06