# 错误处理
# 同步的错误
- 同步代码中的错误会中断后续同步代码的执行
- 后续同步代码被中断后,微任务队列中的任务会继续执行,下一个宏任务也会执行。
console.log(1);
Promise.resolve(2).then(v => {
console.log(v);
});
new Promise(resolve => {
setTimeout(() => {
resolve(3);
}, 2000);
}).then(v => {
console.log(v);
});
console.log(4);
throw new Error('error');
console.log(5);
// 1
// 4
// 2
// Uncaught Error: error
// 3
# 异步的错误
- 异步代码中的错误,不影响当前同步代码的执行
- 异步代码中的错误,中断异步函数中后续的代码执行
console.log(1);
setTimeout(() => {
console.log(2);
throw new Error('error');
console.log(3);
}, 0);
console.log(4);
setTimeout(() => {
console.log(5);
}, 2000);
// 1
// 4
// 2
// Uncaught Error: error
// 5
console.log(1);
new Promise(() => {
setTimeout(() => {
Promise.resolve('2').then(v => {
console.log(v);
});
console.log(7);
throw new Error('error');
resolve('3');
}, 2000);
}).then(v => console.log(v));
console.log(4);
setTimeout(() => {
console.log(5);
}, 0);
setTimeout(() => {
console.log(6);
}, 4000);
// 1
// 4
// 5
// 7
// Uncaught Error: error
// 2
// 6
# try ... catch
try ... catch 语句只能捕获同步的错误,异步的错误捕获不到。try catch 中的错误不会影响外面的代码执行
# promise 中的错误处理
function excutor(resolve, reject) {
// ...
}
function onResolve(resData) {
// ...
}
function onReject(reason) {
// ...
}
function onError(error) {
// ...
}
new Promise(excutor).then(onResolve, onReject).catch(onError);
在 excutor 中的同步抛出的错误会中断 promise,promise 状态不会改变。
在 excutor 中的异步错误无法被捕获,promise 状态不会改变,始终是 pending
在 excutor 中,try ... catch 语句只能捕获同步的错误,异步的错误捕获不到。try catch 中的错误不会影响外面的代码执行。但是 promise 本身状态仍然不会改变,需要调用 resolve 或者 reject 改变。
在 then 中的同步错误会被之后的 catch 捕获。
在 then 中的异步错误,不会被之后的 catch 捕获,相当于 then 中 return 了 undefined,后续的 then 会继续执行。
# async-await 中的错误处理
async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。
async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。
- async 函数内部同步抛出错误,会导致返回的 Promise 对象变为 reject 状态。抛出的错误对象会被 catch 方法回调函数接收到。异步抛出的错误不会影响 async 函数内部同步代码的执行。
async function f() {
setTimeout(() => {
throw new Error('异步出错了');
}, 1000);
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
);
//reject Error: 出错了
// 1s后
// VM5508:3 Uncaught Error: 异步出错了
async function f() {
setTimeout(() => {
throw new Error('异步出错了');
}, 1000);
return '直接return';
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
);
// resolve 直接return
// 1s后
// VM5508:3 Uncaught Error: 异步出错了
- 当 async 中有 await 语句时,async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者同步地抛出错误。
function awaitTime(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('awaitTime done');
}, time);
});
}
async function awaitTest() {
await awaitTime();
throw new Error('出错了,后面的awiat不会执行');
await awaitTime(2000);
console.log('同步log一下信息');
return 'return了结果';
}
awaitTest().then(
v => {
console.log('async 的then,onResolve了:', v);
},
e => {
console.log('async 的then,onReject了:', e);
}
);
// async 的then,onReject了: Error: 出错了,后面的awiat不会执行
- 任何一个 await 语句后面的 Promise 对象变为 reject 状态,那么整个 async 函数都会中断执行。reject 出去的信息作为 async 的 catch 方法的参数
function awaitTime(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('awaitTime done');
}, time);
});
}
async function awaitTest() {
await awaitTime();
await Promise.reject('promise reject');
await awaitTime(2000);
console.log('同步log一下信息');
return 'return了结果';
}
awaitTest().then(
v => {
console.log('async 的then,onResolve了:', v);
},
e => {
console.log('async 的then,onReject了:', e);
}
);
// async 的then,onReject了: promise reject
- 有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个 await 放在 try...catch 结构里面,这样不管这个异步操作是否成功,第二个 await 都会执行。另一种方法是 await 后面的 Promise 对象再跟一个 catch 方法,处理前面可能出现的错误。
function awaitTime(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('awaitTime done');
}, time);
});
}
function asyncFnReject(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('promise error');
}, time);
});
}
async function awaitTest() {
try {
await asyncFnReject();
} catch (err) {
console.log('try catch err', err);
}
await asyncFnReject(2000).catch(err => {
console.log('promise catch', err);
});
console.log('同步log一下信息');
return 'return了结果';
}
awaitTest().then(
v => {
console.log('async 的then,onResolve了:', v);
},
e => {
console.log('async 的then,onReject了:', e);
}
);
// try catch err promise error
// promise catch promise error
// 同步log一下信息
// async 的then,onResolve了: return了结果
- 如果 await 后面的异步操作出错(同步地抛出错误),那么等同于 async 函数返回的 Promise 对象被 reject。
async function f() {
await new Promise(function(resolve, reject) {
throw new Error('出错了');
// 异步错误将导致该promise始终为pending,async也始终为pending
// setTimeout(() => {
// throw new Error('出错了');
// }, 0);
});
console.log('同步 log 信息');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e));
// Error:出错了
- 如果有多个 await 命令,可以统一放在 try...catch 结构中。
function awaitTime(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('awaitTime done');
}, time);
});
}
function asyncFnReject(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('promise error');
}, time);
});
}
async function awaitTest() {
try {
await awaitTime();
console.log(1);
await asyncFnReject();
console.log(2);
await asyncFnReject();
console.log(3);
} catch (err) {
console.log('try catch err', err);
}
console.log('同步log一下信息');
return 'return了结果';
}
awaitTest().then(
v => {
console.log('async 的then,onResolve了:', v);
},
e => {
console.log('async 的then,onReject了:', e);
}
);
// 1
// try catch err promise error
// 同步log一下信息
// async 的then,onResolve了: return了结果
← Tree-Shaking useMemo →