异常就是程序出现了意料之外的情况,影响了程序最终的呈现结果。所以我们开发的时候就非常有必要未雨绸缪,进行异常监控,以应对突如其来的问题,既可以增强用户体验,我们开发者也能远程定位问题,尤其是移动端
尽管对 JS 而言,异常一般只会使当前执行的任务中止,基本不会导致崩溃。
可异常监控却是一个完善的前端方案必须具备的,接下来就针对我们前端,需要做的异常一一说明
两者结合更好
window.onerror = function (msg, url, row, col, error) {
console.table({ msg, url, row, col, error: error.stack })
let errorMsg = {
type: 'javascript',
// msg错误消息,error是错误对象,这里拿的是error.stack(异常信息)
msg: error && error.stack ? error.stack || msg,
// 发生错误的行数
row,
// 列数,也就是第几个字符
col,
// 发生错误的页面地址
url,
// 发生错误的时间
time: Date.now()
}
// 然后可以把这个 errorMsg 存到一个数组里,统一上报
// 也可以直接上报
Axios.post({ 'https://xxxx', errorMsg })
// 如果return true,错误就不会抛到控制台
}
上报有两种方式,一种是如上面代码中的用 AJAX,会有跨域所以需要服务端支持;还有一种是用 Image 对象,这有一个好处就是图片请求没有跨域;注意URL长度不要超过限制就行。后面的例子中就不一一列举了
let url = 'https://xxx' + '错误信息'
new Image.src = url
捕获 iframe 异常和 JS 执行差不多
<iframe src="xxx.html"></iframe>
<script>
window.iframe[0].onerror = function (msg, url, row, col, error) {
//和上面 JS 异常一样
})
</scrpt>
使用 addEventListener('error', callback, true) 在捕获阶段捕捉资源加载错误信息,然后上报服务器
addEventListener('error', e => {
const targe = e.target
if(target != window){
//这里收集错误信息
let errorMsg = {
type: target.localName, // 错误来源名称。比如图片这里就是'img'
url: target.src || target.href, //错误来源的链接
// .... 还需要其他信息可以自己补充
}
// 把这个 errorMsg 存到一个数组里,然后统一上报
// 或者直接上报
Axios.post({ 'https://xxxx', errorMsg })
}
}, true)
使用 addeventListener('unhandledrejection',callback)捕获 Promise 错误。不过捕捉不到行数
window.addEventListener("unhandledrejection", (e) => {
console.log(e)
let errorMsg = {
type: 'promise',
msg: e.reason.stack || e.reason
// .....
}
Axios.post({ 'https://xxxx', errorMsg })
// 如果return true,错误就不会抛到控制台
})
new Promise(() => {
s
})
打印出来是这么个东西
errorHandle
Vue为组件呈现函数和监视程序期间没有捕获的错误分配的一个处理程序。不过这个方法一旦捕获取错误后,错误就不会抛到控制台
Vue.config.errorHandler = (err, vm, info) => {
// err 错误处理
// vm vue实例
// info 是特定于vue的错误信息,比如哪个生命周期勾子
// 如果需要把错误抛到控制台,需要在这里加上这一行
console.error(err)
}
warnHandle
是Vue警告分配一个自定义处理程序。不过只在开发环境有效,生产环境会被自忽略
Vue.config.warnHandle = (msg, vm, trace){
// trace 是组件层次结构
}
renderError
默认的渲染函数遇到错误时,提供了一个代替渲染输出的。这个和热重新加载一起用会很棒
new Vue({
render (h){
throw new Error('oops')
},
renderError (h, err){
return h('per',{ style: { color: red } }, err.stack)
}
}).$mount('#app')
errorCaptured
任何派生组件捕获错误时调用。它可以 return false 来阻止错误传播。可以在这个勾子里修改组件状态。不过如果是在模板或呈现函数里有条件语句,在捕获到错误时,这些条件语句会短路,可能进入一个无限渲染循环
Vue.component('ErrorBoundary',{
data: () => { ... }
errorCaptured(err, vm, info){
// err 错误信息
// vm 触发错误的组件实例
// info 错误捕获位置信息
return false
}
})
getDerivedStateFromError
React 也有自带的捕获所有子组件中错误的方法,这个生命周期会在后代组件抛出错误时被调用。注意这个是在渲染阶段调用的,所以不允许出现副作用
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显降级 UI
return { hasError: true }
}
}
componentDidCatch
这个生命周期也会在后代组件抛出错误时被调用,但是不会捕获事件处理器和异步代码的异常。它会在【提交】阶段被调用,所以允许出现副作用
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
}
componentDidCatch(error, info){
// error 错误信息
// info.componentStack 错误组件位置
}
}
说了前端可能发生的各种异常处理,那么后端异常呢?前端容灾就是
前端容灾指的因为各种原因后端接口挂了(比如服务器断电断网等等),前端依然能保证页面信息能完整展示。比如 banner 或者列表之类的等等数据是从接口获取的,要是接口获取不到了,怎么办呢?
首先,使用 LocalStorage
在接口正常返回的时候把数据都存到 LocalStorage ,可以把接口路径作为 key,返回的数据作为 value
然后之次再请求,只要请求失败,就读取 LocalStorage,把上次的数据拿出来展示,并上报错误信息,以获得缓冲时间
同时,每次更新都要备份一份静态数据放到CDN
在接口请求失败的时候,并且 LocalStorage 也没有数据的情况下,就去 CDN 摘取备份的静态数据
假如不只是接口数据,整个 html 都想存起来,就可以使用 Service Worker 做离线存储
利用 Service Worker 的请求拦截,不管是存接口数据,还是存页面静态资源文件都可以
// 拦截所有请求事件 缓存中有请求的数据就直接用缓存,否则去请求数据
self.addEventListener('fetch', e => {
// 查找request中被缓存命中的response
e.respondWith(caches.match(e.request).then( response => {
if (response) {
return response
}
console.log('fetch source')
}))
})
做好这些,整个网站就完全可以离线运行了
如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star: http://github.crmeb.net/u/defu 不胜感激 !
大多时候(除:网络故障与请求被阻止外),使用fetch()返回的 Promise被标记为resolve,包括(接收到一个代表错误的 HTTP 状态码时,HTTP 响应的状态码是 404 或 500,但是,此时会将 resolve 的返回值的 ok 属性设置为 false
JavaScript 错误和一般处理 throw new Error(\'something went wrong\') 会在 JavaScript 中创建一个错误实例,并停止脚本的执行,除非你对错误做了一些处理。当你作为 JavaScript 开发者开启自己的职业生涯时,你自己很可能不会这样做
ECMA-262第3版引入了try catch语句,作为JavaScript中处理异常的一种标准方式。基本的语法如下所示。但是在前端js代码中很少看到try catch语句,并不是所以代码都需要加try catch来作得不偿失的保险
在前端项目中,由于JavaScript本身是一个弱类型语言,加上浏览器环境的复杂性,网络问题等等,很容易发生错误。做好网页错误监控,不断优化代码,提高代码健壮性是一项很重要的工作
异常(Exception)是一种错误处理机制,用于在指定的错误发生时改变脚本的正常流程。当异常被触发时,当前代码状态被保存,代码执行被切换到预定义的异常处理器函数(如果有)
js中的异常处理语句有两个,一个是try……catch……,一个是throw。try……catch用于语法错误,错误有name和message两个属性。throw用于逻辑错误。对于逻辑错误,js是不会抛出异常的
try中没有抛出异常,则catch语句不执行,如果有finally语句,则接着执行finally语句,继而接着执行finally之后的语句;不管是否try...catch,finally都会被执行。当try...catch中有return的话,finally后会执行try...catch中的return
很多开发者在开发过程中都会遇到异常,处理过程大同小异:捕获然后处理,事实上也确实是如此。只是从laravel自带的Exception入手,谈一谈怎样用一个更好的方式处理错误信息。
首先一个常识就是,在浏览器执行JS脚本过程中,当出现脚本错误,并且你没有手动进行异常捕捉时,他会在浏览器下面出现黄色的叹号,这是正常的
最近观察项目 CI 跑的情况如何时,会偶尔发现一两个镜像虽然构建成功但是容器跑不起来的情况。究其原因,是因为一个 exit code 的问题
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!