前端异常处理,常见的场景是在“异步请求”的操作过程当中,所谓“异常”---就是“不正常”,程序的运行不符合我们的预期。
程序“正常”的处理,是我们在开发过程当中的“重中之重”,是必要的“硬性指标”。
而“异常处理”,很多时候可能连“指标”都没有,更谈不上什么“硬性指标”了,所以,在开发当中是很容易被忽略的一个“主题”。
但是,“提高用户体验”与“提高程序可控性”又是两个永恒的主题,“枝繁叶茂”就是我们追求的目标(枝---主功能;叶---细节;)。
在追求“枝繁叶茂”的过程当中,“异常处理”就是细节当中的重中之重,故此,对此进行了如下实践:
常见的“异步请求”操作:1.ajax(以$.ajax为例);2.fetch;
此处对这两种方式的“异常处理”进行了实践(包括try,catch,finally,throw error,new Error(),console.error的运用),以fetch实践为主,由于fetch返回的实际上是promise对象,为了方便查看测试效果,此处直接使用promise对象代替说明。
一.$.ajax相关
$.ajax({ url: "/hello?name=平凡视界", type: "GET", success: (data) =>{ //成功相关处理 console.log('返回数据',data) }, error: (err) =>{ //错误相关处理 404属于该处理(经测试) //还可能是"timeout", "error", "notmodified" 和 "parsererror"。 console.log('错误处理',err); } });
二.fetch相关
实践1:当程序运行遇到 throw error 时,JS引擎会停止后续业务执行,程序直接进入catch环节;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ const error = new Error('粗错啦~'); throw error; //JS引擎会停止后续业务执行,程序直接进入catch环节 res('异步OK'); },3000) }) .then((data) =>{ console.log('异步执行OK',data);//并没有执行 },(data) =>{ console.log('异步执行拒绝',data);//并没有执行 }) .then((data) =>{ console.log('二次then执行OK',data);//并没有执行 }) .catch((err) =>{ console.error('嘿',err);//执行OK })
实践2:当程序 resolve 时,在后续then操作当中注册的resolve handle会顺次执行,注册的reject handle与catch并未执行;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ res('异步OK'); },3000) }) .then((data) =>{ console.log('异步执行OK',data);//执行OK },(data) =>{ console.log('异步执行拒绝',data);//并没有执行 }) .then((data) =>{ console.log('二次then执行OK',data);//执行OK }) .catch((err) =>{ console.error('嘿',err);//并没有执行 })
实践3:当程序 reject 时,在后续“子1级”then操作当中注册的reject handle执行---验证1,其他注册的resolve handle与catch并未执行;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ rej('异步失败'); },3000) }) .then((data) =>{ console.log('异步执行OK',data);//并没有执行 },(data) =>{ console.log('异步执行拒绝',data);//执行OK }) .then((data) =>{ console.log('二次then执行OK',data);//执行OK }) .catch((err) =>{ console.error('嘿',err);//并没有执行 })
实践4:当程序 reject 时,在后续“子2级”then操作当中注册的reject handle执行---验证2(子1级中,并没有注册reject handle相关的处理机制,故被在“子2级”then操作当中注册的reject handle接收,并执行处理),其他注册的resolve handle与catch并未执行;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ rej('异步失败'); },3000) }) .then((data) =>{ console.log('异步执行OK',data);//并没有执行 }) .then((data) =>{ console.log('二次then执行OK',data);//并没有执行 },(data) =>{ console.log('二次then"接收"reject异步"执行结果"(拒绝)',data);//执行OK }) .catch((err) =>{ console.error('嘿',err);//并没有执行 })
实践5:当程序 reject 时,在后续“子4级”then操作当中注册的reject handle执行---验证2(“子1级”至“子3级”中,并没有注册reject handle相关的处理机制,故被在“子4级”then操作当中注册的reject handle接收,并执行处理),其他注册的resolve handle与catch并未执行;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ rej('异步失败'); },3000) }) .then((data) =>{ console.log('异步执行OK1',data);//并没有执行 }) .then((data) =>{ console.log('异步执行OK2',data);//并没有执行 }) .then((data) =>{ console.log('异步执行OK3',data);//并没有执行 }) .then((data) =>{ console.log('二次then执行OK4',data);//并没有执行 },(data) =>{ console.log('二次then"接收"reject异步"执行结果"(拒绝)',data);//执行OK }) .catch((err) =>{ console.error('嘿',err);//并没有执行 })
实践6:当程序 reject 时,“子1级”至“子4级”中,并没有注册reject handle相关的处理机制,故被catch接收,并执行处理,其他注册的resolve handle并未执行;
new Promise((res, rej) =>{ console.log('异步开始。。。'); setTimeout(() =>{ rej('异步失败'); },3000) }) .then((data) =>{ console.log('异步执行OK1',data);//并没有执行 }) .then((data) =>{ console.log('异步执行OK2',data);//并没有执行 }) .then((data) =>{ console.log('异步执行OK3',data);//并没有执行 }) .then((data) =>{ console.log('异步执行OK4',data);//并没有执行 }) .catch((err) =>{ console.error('嘿',err);//执行OK-----rej的时候,“其后程序”没有对rejct进行相应处理时, //catch会接收该reject响应,并进行处理 })
三.try,catch,finally,throw error,new Error(),console.error的运用;
try{ console.log("test"); throw new Error('出错了吧?');//throw 后面的参数,会被catch中的e接收}catch(e){ // e == '出错了吧?' console.error(e);// 出错了吧?}finally{ console.log('怎么都会执行');// 执行OK}
四.总结
1.当程序执行遇到“throw error”时,JS引擎会停止后续业务执行,程序直接进入catch环节;
(promise对象,try包裹的代码块)
2.promise:
--- resolve:
大多时候(除:网络故障与请求被阻止外),使用fetch()返回的 Promise被标记为resolve,
包括(接收到一个代表错误的 HTTP 状态码时,HTTP 响应的状态码是 404 或 500,但是,此时会将 resolve 的返回值的 ok 属性设置为 false,
如果需要进行细分,可以根据该属性进行细分---在“异步请求”中,处理的大多数异常或error针对该阶段异常)
--- reject:
使用fetch()返回的 Promise被标记为 reject的情况仅有两种(1.网络故障;2.请求被阻止(如“跨域”))
说明:当程序在reject时,如果后续没有注册“相关程序”来接收处理,那么,该reject会被catch处理,在该reject发生之后注册的一切reslove 业务将不会被执行;
当程序在reject时,如果后续有注册“相关程序”来接收处理,那么,该reject会被所“注册”的函数进行处理,在该注册函数之后的一切reslove 业务不会受该reject的影响,会依次执行,同时,catch不会被“该reject”触发;
3.try catch finally:
try{ #1运行代码 }catch(err){ #1出错,程序直接进入该环节 }finally{ #1出错 or 正常,程序都进入该环节 }