JavaScript 非常的提防与监控

一套完美的前端体系应少不了异常统计与监控,纵然有充足的质量保证体系,不免会涌现一些意料之外的事,尤其是在庞杂的网路环境和运转环境之下。为了保证代码的硬朗性以及页面的稳定性,我们从多个方面来做异常的提防和监控。

三种思绪

主动防备

关于我们操纵的数据,尤其是由 API 接口返回的,经常会有一个很庞杂的深层嵌套的数据结构。为了代码的硬朗性,许多时刻须要对每一层接见都作空值推断,就像如许:

props.user &&
props.user.posts &&
props.user.posts[0] &&
props.user.posts[0].comments &&
props.user.posts[0].comments[0]

相似的代码人人能够都写过,没写过也许也见到他人写过。看起来确切相本地不美观,有句话说得很棒:

The opposite of beautiful is not ugly, but wrong.

我们得找到一种,更简朴、更文雅、更平安的体式格局来处置惩罚这类情况。参考这篇文章:Safely Accessing Deeply Nested Values In JavaScript,文章提到借助 Ramda、Lenses、Lodash 以及 Immutable.js 等类库的体式格局,并供应一个异常简洁明了的原生解决计划:

function getIn(p, o) {
    return p.reduce(function(xs, x) {
        return (xs && xs[x]) ? xs[x] : null;
    }, o);
}

接下来我们如许接见就能够了:

getIn(['user', 'posts', 0, 'comments'], props)

假如一般接见到,则返回对应的值,不然返回 null

这里供应的只是主动防备的一种情况,关于怎样编写更平安的代码这里不作深切睁开。

全局监控

浏览器供应 window.onerror API 来协助我们举行全局的毛病监控:

  • 当 JavaScript 运转时毛病(包括语法毛病)发作时,会实行 window.onerror()`
  • 当一项资本(如 <img><script> )加载失利,能被单一的 window.addEventListener 捕获
/**
 * @param  {String} message 毛病信息
 * @param  {String} source  发作毛病的剧本URL
 * @param  {Number} lineno  发作毛病的行号
 * @param  {Number} colno   发作毛病的列号
 * @param  {Object} error   Error对象
 */
window.onerror = function(message, source, lineno, colno, error) {
  // ...
}

个中 error 对象包括细致的毛病客栈信息,在 IE9 之前,没有这个参数。

针对性捕获 try..catch

能够经由过程 try..catch 来主动抓取毛病,想要对一段代码 try..catch,我们能够如许:

try {
  // ...
} catch (error) {
  handler(error)
}

对一个函数做 try..catch 封装:

function tryify(func) {
  return function() {
    try {
      return func.apply(this, arguments)
    } catch (error) {
      handleError(error)

      throw error
    }
  }
}

为何是 script error

计划已明白,但另有一些问题。在检察 JavaScript 毛病统计时,发明 80% 以上都是 “script error”。本来,当加载自差别域的剧本中发作语法毛病时,为防止信息泄漏,语法毛病的细节将不会报告,而代之简朴的 “Script error.”

而在大多数情况下,我们的静态资本放在特地的 CDN 服务器上,跟站点并不在一个域,所以假如只是简朴的抓取,只会获得一堆意义不大的 script error

解决计划:

  • 增添 CORS 支撑
  • 运用 try..catch

增添 CORS 支撑

须要做两点:

1.在 script 便签增添 crossorigin,默认值 crossorigin="anonymous"

<script src="//xxx.com/example.js" crossorigin></script>

在 require.js 里供应一个 onNodeCreated hook,供我们供应扩大,要增添 crossorigin 属性,以下所示:

<script>
// 假如在 require.js 加载之前定义了 requirejs,require.js 会将其作为一个对象传入 requirejs.config
var requirejs = {
  onNodeCreated: function(node, config, id, url) {
    node.setAttribute('crossorigin', 'anonymous')
  }
}
</script>
<script src="//xxx.com/require.js" charset="utf-8"></script>

在 2.2.0 版本以上可用(很遗憾的是,现在的集成解决计划版本恰好低于这个版本)。

2.同时在 CDN 服务器增添相应头 access-control-allow-orgin,设置许可接见 CORS 的域,不然浏览器直接将制止加载。

try..catch

这一点上面也有提到,算是一种比较通用,可定制强的计划。固然,在机能上也会有一些消耗。

综合斟酌,try..catch 通用性更好,但由于其在机能方面的一些消耗,CORS 优于 try..catch

一个监控小东西

随后,引见一个 JavaScript stack trace 的小东西:https://github.com/CurtisCBS/… ,东西由 Curtismirreal 共同完成。

主如果用于捕获页面 JavaScript 异常报错,捕获异常范例包括:

  • JavaScript runtime 异常捕获 √
  • 静态资本 load faided 异常捕获 √
  • console.error 的异常捕获 √
  • try..catch 毛病捕获 √

运用体式格局也很简朴,但运用 script mode 引入文件后,挪用 init 函数,举行初始化设置和监听

<script src="//unpkg.com/jstracker@latest/dist/jstracker.js"></script>

<script>
  jstracker.init({
    delay: 1000,
    maxError: 10,
    sampling: 1,
    report: function(errorLogs) {
      console.table(errorLogs)
    }
  })
</script>

假如是运用 module mode,以下:

// npm install jstracker --save
import jstracker from 'jstracker'

jstracker.init({
  concat: false,
  report: function(errorLogs) {
    // console.log('send')
  }
})

假如要运用 try..catch 捕获,jstracker 暴露出一个 tryJS 对象,能够处置惩罚 try..catch 包装,就像如许:

import jstracker from 'jstracker';

this.handleSelect = jstracker.tryJS.wrap(this.handleSelect);

一切毛病信息一致由 report 函数处置惩罚,能够在此之上做数据处置惩罚:

// ubt.js
import jstracker from 'jstracker';
import utility from 'utility';

jstracker.init({
    concat: false,
    report: function(errorLogs) {
        const errorLog = errorLogs[0];
        errorLog.ua = window.navigator.userAgent;
        ubtTracker.send(errorLog);
    }
});

const ubtTracker = {
    key: {
        UBT_JS_TRACKER: 'xxxx-xxxx-xxxx'
    },

    send(data) {
        const value = utility.deserializeUrl(data);
        
        xxxx.send(['trace', this.key.UBT_JS_TRACKER, value]);
    }
};

function wrapContext(ctx) {
    for (const func in ctx) {
        ctx[func] = jstracker.tryJS.wrap(ctx[func]);
    }
}

export {
    wrapContext,
    ubtTracker,
    jstracker
};

概述

作为开发者以及项目维护者的身份,我们应该编写更平安硬朗的代码。但由于环境的多样性,不管再完美的测试,code review 都不免都所疏漏,我们须要一套监控体系来完美全部前端体系。

在监控的时刻,出于同源平安策略没法拿到正确的毛病信息,在此,有两种解决计划:

  • 增添 CORS 支撑
  • 运用 try..catch 举行异常捕获

末了,我们对全部监控事情封装了一个基本的中心,能够监控 JavaScript Runtime 异常,资本加载异常,以及 try..catch 捕获异常等,并给出一个现实事情中的示例。

    原文作者:离独逸
    原文地址: https://segmentfault.com/a/1190000009875977
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞