让你的前端组件混沌一下?

avatar
SugarTurboS Club @SugarTurboS

github blog:github.com/SugarTurboS…

什么是混沌

混沌即混沌工程,首先我们得知道混沌工程是什么。

混沌工程起源于Netflix公司,Netflix公司的工程师创建了一种验证服务可靠性的测试工具Chaos Monkey。使用这个工具,可以在我们的web系统中随机的制造一些麻烦,比如触发网络异常,流量激增,容器退出等异常,我们可以在这些异常发生时,观察我们的系统是否依旧按照我们预期的方式运行。假设在流量激增突破承载能力的场景下,我们的系统是否会触发熔断机制来保障功能稳定运行。该工具最大的作用是,让故障在造成重大损失之前暴露出来,给工程师提供足够的时间和机会来修复问题。随着时间的发展,混动工具演变成了一套方法论,用来指导工程师如何让系统提前暴露问题,及时修复问题。

目前国内很多大厂都有相关的混沌工程实践,不过多数都在后端领域实践,在前端中实践混沌工程的相对较少。那在前端中,如何将混沌的方法论和思想落地呢?

在这里插入图片描述

混沌组件

近期在逛github的时候,找到了一个让react组件混沌起来的开源库 react-chaos。这个组件的功能非常简单,它提供了一个高阶组件,该高阶组件的功能是通过一个随机数,让组件随机的Throw Exception出来。如果你的组件没有处理异常的代码,那组件在页面就不会渲染出来的,并且在控制台中会显示出相应的错误信息。出错时的效果如下图所示:

在这里插入图片描述 我们来看看他的源码

const withChaos = (
  WrappedComponent: React.ElementType,
  level: Level,
  errorMessage?: string,
  runInProduction?: boolean
): WithChaosReturn => {
  if (process.env.NODE_ENV === 'production' && !runInProduction) {
    console.warn(
      `You tried to use React Chaos in production. You probably didn't mean to do this. Chaos will not occur in production.`
    );
    return WrappedComponent;
  }

  if (process.env.NODE_ENV === 'production' && runInProduction) {
    console.warn('You are running React Chaos in production.');
  }
  return class extends React.Component {
    render() {
      return (
        <Chaos
          level={level}
          errorMessage={errorMessage}
          runInProduction={runInProduction}
        >
          <WrappedComponent {...this.props} />
        </Chaos>
      );
    }
  };
};

高阶组件withChaos会把传入的原始组件用Chaos组件wrap之后返回,Chaos除了实现混沌相关的逻辑外,没有其他的用途,下面是Chaos的源码

export function Chaos({
  children,
  level,
  errorMessage,
  runInProduction,
}: Args): JSX.Element | null {
  return createChaos(level, errorMessage, runInProduction) ? null : children;
}

Chaos组件中通过createChaos函数返回的值来判断是否渲染children组件

if (process.env.NODE_ENV === 'production' && !runInProduction) {
    /** Chaos will not occur in production. */
    return false;
  }

  if (typeof level !== 'number') {
    throw new Error(
      `Please provide a number level. You provided: ${typeof level}`
    );
  }

  const chaosLevel = level !== 5 ? convertChaosLevel(level) : 0.5;
  const chaosOn = Math.random() >= chaosLevel;
  if (chaosOn) {
    throw new Error(errorMessage);
  }
  return false;

createChaos函数的核心逻辑就是创建一个随机数来实现组件随机抛异常。

这个库功能和原理虽然简单,但它其实是混沌思想在前端的一个非常好的实践。它能让你检测出你的react组件是否对代码异常有比较完善的处理机制。

构建插件

如果想要让组件具有随机抛异常的功能,需要通过react-chaos的withChaos来将组件HOC一下。当你项目中组件非常多且想都增加这个功能的时候,如果每个组件都去手动withChaos然后返回,那工作量会比较大。所以我这边写了一个babel插件,可以在webpack构建的时候,自动的将react组件使用withChaos包裹并返回。

Github地址:

github.com/SugarTurboS…

这个插件所做的事情就是通过babel提供的操作AST的能力,将源代码转换为带有withChaos调用的代码

import React from 'react'

function Hello(){
    return (
        <div>Hello</div>
    )
}

export default Hello;

转换后

import React from 'react'
import withChaos from 'react-chaos'

function Hello(){
    return (
        <div>Hello</div>
    )
}

export default withChaos(Hello, |chaosLevel|);

通过这个插件,就能轻松的将react-chaos加入到项目中使用了。