异步错误处理 -- 时机
1、编写JavaScript代码时,我们要时刻牢记,JavaScript引擎是一个事件驱动的执行引擎,代码总是以单线程执行,
而回调函数的执行需要等到下一个满足条件的事件出现后,才会被执行。
例如,setTimeout()
函数可以传入回调函数,并在指定若干毫秒后执行:
function printTime() { console.log('It is time!'); } setTimeout(printTime, 1000); console.log('done'); // 上面的代码会先打印done,1秒后才会打印It is time!。
2、如果printTime()
函数内部发生了错误,我们试图用try包裹setTimeout()
是无效的
function printTime() { throw new Error(); } try { setTimeout(printTime, 1000); console.log('done'); } catch (e) { console.log('error'); } //不会捕捉到异常,JS引擎报错
// VM3520:5 Uncaught Error at printTime (eval at <anonymous> (extension.js?v=1.0-b1b83dc-2019-05-25T01:51:58Z:61), <anonymous>:5:11)
原因就在于调用setTimeout()
函数时,传入的printTime
函数并未立刻执行!
紧接着,JavaScript引擎会继续执行console.log('done');
语句,而此时并没有错误发生。
直到1秒钟后,执行printTime
函数时才发生错误,但此时除了在printTime
函数内部捕获错误外,外层代码并无法捕获。
所以,涉及到异步代码,无法在调用时捕获,原因就是在捕获的当时,回调函数并未执行。
3、类似的,当我们处理一个事件时,在绑定事件的代码处,无法捕获事件处理函数的错误。
<form> <input id="x"> + <input id="y"> <button id="calc" type="button">计算</button> </form> try { $btn.click(function () { var x = parseFloat($('#x').val()), y = parseFloat($('#y').val()), r; if (isNaN(x) || isNaN(y)) { throw new Error('输入有误'); } r = x + y; alert('计算结果:' + r); }); } catch (e) { alert('输入有误!'); }
// VM3523:16 Uncaught Error: 输入有误
// at HTMLButtonElement.eval (eval at <anonymous> (extension.js?v=1.0-b1b83dc-2019-05-25T01:51:58Z:61), <anonymous>:16:19)
// at HTMLButtonElement.dispatch (jquery.js:3)
// at HTMLButtonElement.r.handle (jquery.js:3)
修改代码如下:
$btn.click(function () { try { var x = parseFloat($('#x').val()), y = parseFloat($('#y').val()), r; if (isNaN(x) || isNaN(y)) { throw new Error('输入有误'); } r = x + y; alert('计算结果:' + r); } catch (e) { alert('输入有误!'); } });
转自:https://www.liaoxuefeng.com/wiki/1022910821149312/1120880431288064