把一些前后端概念性比较强的理念放在这里,本片涉及微前端、serverless、wasm、单元测试等
https://segmentfault.com/a/1190000038774393?utm_source=sf-related
WebAssembly
wasm并不是一种编程语言,而是一种新的字节码格式,目前,主流浏览器都已经支持 wasm。与 JavaScript 需要解释执行不同的是,wasm字节码和底层机器码很相似可快速装载运行,因此性能相对于 JavaScript 解释执行有了很大的提升。
WebAssembly(缩写为 Wasm)是基于堆栈的虚拟机的二进制指令格式。Wasm 被设计为可移植目标,用于编译高级语言(如 C / C ++ / Rust),从而可以在 Web 上为客户端和服务器应用程序进行部署。
WebAssembly 的开放标准是在 W3C 社区组(包括来自所有主要浏览器的代表)和 W3C 工作组中开发的。
WebAssembly 或称 wasm 是一个实验性的低端编程语言,应用于浏览器内的客户.WebAssembly 是便携式的抽象语法树,被设计来提供比 JavaScript 更快速的编译及运行。WebAssembly 将让开发者能运用自己熟悉的编程语言(最初以 C/C++ 作为实现目标)编译,再藉虚拟机引擎在浏览器内运行。
WebAssembly 的开发团队分别来自 Mozilla、Google、Microsoft、Apple,代表着四大网络浏览器 Firefox、Chrome、Microsoft Edge、Safari。
2017 年 11 月,以上四个浏览器都开始实验性的支持 WebAssembly。
WebAssembly 于 2019 年 12 月 5 日成为万维网联盟(W3C)的推荐,与 HTML,CSS 和 JavaScript 一起,成为 Web 的第四种语言。
WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++ 等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。
特点
高效快捷
Wasm 堆栈机设计为以节省大小和加载时间的二进制格式进行编码。WebAssembly 旨在通过利用广泛平台上可用的通用硬件功能,以本机速度执行。
对于网络平台而言,WebAssembly 具有巨大的意义——它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在 Web 中运行。
在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在 Web 中。
WebAssembly 被设计为可以和 JavaScript 一起协同工作——通过使用 WebAssembly 的 JavaScript API,你可以把 WebAssembly 模块加载到一个 JavaScript 应用中并且在两者之间共享功能。
这允许你在同一个应用中利用 WebAssembly 的性能和威力以及 JavaScript 的表达力和灵活性,即使你可能并不知道如何编写 WebAssembly 代码。
而且,更棒的是,这是通过 W3C WebAssembly Community Group 开发的一项网络标准,并得到了来自各大主要浏览器厂商的积极参与。
安全
WebAssembly 描述了一种内存安全的沙盒执行环境,该环境甚至可以在现有 JavaScript 虚拟机内部实现。当嵌入 Web 时,WebAssembly 将强制执行浏览器的同源和权限安全策略。
传统从 JS 代码,在浏览器端运行,是有被拿到源代码的可能(即使你加密了);
WebAssembly 使用二进制 (.wasm文件)的形式,在这方面跨出一步
开放且可调试
WebAssembly 旨在以文本格式漂亮地打印,以便手工调试,测试,实验,优化,学习,教学和编写程序。在 Web 上查看 Wasm 模块的来源时,将使用文本格式。
开放式网络平台的一部分
WebAssembly 旨在维护 Web 的无版本,经过功能测试和向后兼容的性质。WebAssembly 模块将能够调用和退出 JavaScript 上下文,并通过可从 JavaScript 访问的相同 Web API 访问浏览器功能。WebAssembly 还支持非 Web 嵌入。
可移植——能够在不同硬件平台和操作系统上运行。
保密——WebAssembly是一门低阶语言,是一种紧凑的二进制格式,具有良好的保密性。
安全——WebAssembly被限制运行在一个安全的沙箱执行环境中。像其他网络代码一样,它遵循浏览器的同源策略和授权策略。
兼容——WebAssembly的设计原则是与其他网络技术和谐共处并保持向后兼容。
历史
JavaScript一开始就是动态类型解释性语言,动态类型解释性语言的一大特点就是灵活和慢。
所以JavaScript和所有的动态类型语言一样,天生会比静态类型语言慢。
而随着网页应用越来越复杂,JavaScript的运行性能就必须跟着提高。
那么为什么动态类型语言,如Python、PHP、JavaScript就会比C/C++等静态类型语言慢呢?
JS慢
我们来看一个最简单的情况,实现c = a + b加法运算,如果是C/C++语言,实现步骤大致如下:
内存a里取值到寄存器
内存b里取值到寄存器
算加法
把结果放到内存c
如果是JavaScript大致会经历哪些步骤呢?
代码编译
当前上下文是否有变量a,没有的话去上一层寻找,直到找到,或到达最外层上下文
当前上下文是否有变量b,没有的话去上一层寻找,直到找到,或到达最外层上下文
判断变量a的变量类型
判断变量b的变量类型
变量a、变量b是否需要进行类型转化,并进行类型转化
算加法
运行结果赋值给c
我们可以看到,二者的整个流程还是有比较大的区别
JIT
JIT(just-in-time compilation):如果在执行c = a + b的时候,a和b几乎都是int类型,那么是否可以去掉类型判断,类型转化的步骤,用接近C/C++的方式来实现加法运算,并把执行代码直接编译成机器码,直接运行,不需要再次编译。
Google 在 2009 年在 V8 中引入了 JIT 技术,JavaScript的执行速度瞬间提升了 20 - 40 倍的速度。
JIT的问题是并不是所有的代码都能得到很好的提升,因为JIT基于运行期分析编译,而JavaScript是一个没有类型的语言,所以当代码中的类型经常变化的时候,性能提升是有限的。
比如
function add (a, b)
{
return a + b
}
var c = add(1, 2);
JIT 看到这里, 觉得好开心, 马上把 add编译成
function add (int a, int b)
{
return a + b
}
但是,很有可能,后面的代码是这样的
var c = add(“hello”, “world”);
JIT 编译器的可能当时就哭了,因为add已经编译成机器码了,只能推到重来
asm.js
2012年,Mozilla 的工程师 Alon Zakai 在研究LLVM编译器时突发奇想:许多 3D 游戏都是用 C / C++语言写的,如果能将 C / C++语言编译成 JavaScript 代码,它们不就能在浏览器里运行了吗?
于是,他开始研究怎么才能实现这个目标,为此专门做了一个编译器项目Emscripten。这个编译器可以将 C / C++代码编译成 JS代码,但不是普通的JS,而是一种叫做 asm.js的 JavaScript变体。
asm.js它的变量一律都是静态类型,并且取消垃圾回收机制。当浏览器的JavaScript引擎发现运行的是 asm.js时,就会跳过语法分析这一步,将其转成汇编语言执行。asm.js的执行速度可以达到原生代码的50%。
asm.js的一般工作流程为:
C/C++
LLVM
Emscripten
JavaScript
但asm.js还是存在几个问题:
- 仅有
FirFox的浏览器有良好的支持 - 代码传输还是与现有方式一样,传输源码,本地编译
Mozilla,Google,Microsoft, 和Apple 觉得 Asm.js 这个方法有前途,想标准化一下,大家都能用。
便诞生了WebAssembly。
有了大佬们的支持,WebAssembly比 asm.js要激进很多。 WebAssembly连编译 JS这种事情都懒得做了,不是要 AOT吗? 我直接给字节码好不好?(后来改成 AST 树)。对于不支持 Web Assembly的浏览器, 会有一段JavaScript把 Web Assembly重新翻译为 JavaScript运行。
2019年12月5日,万维网联盟(W3C)宣布 WebAssembly成为正式标准
Serverless
Serverless 是前端圈近两年比较火热的词汇,通过 Serverless 这种服务形态,用户在使用对应的服务时,不需要关心或较少关心服务器的硬件资源、软件资源、稳定性等等,完全托管给云计算厂商,用户只需要专注自己应用代码本身,上传执行函数到相应云计算平台,按照函数运行的时长按量付费即可
演进史
云计算诞生后,用户可以直接购买云主机(VM),把基础物理硬件和网络的管理都交由供应商管理,多用户租用一台物理机,减少了用户硬件管理成本,我们通常称之为 IaaS(Infrastructure-as-a-Service)。
随着软件的发展和容器技术的兴起,计算环境由 VM 发展到更小粒度的容器,在容器中可以运行不同的软件服务,PaaS(Platform-as-a-Service) 和 CaaS(Container-as-a-Service) 也开始映入眼帘。用户使用平台基础软件如 Database、消息等开发自己的应用,使用容器镜像构建和部署应用,最后托管给平台。
继续向前发展,应用的运行演变为更细粒度函数的运行,用户开发特定业务的处理函数,托管给函数平台,按需使用相关的后端服务,通过特定条件的触发完成开发者业务逻辑函数的计算。用户无需为应用持续付费,只需支付函数运行时产生的资源消耗费用,而这,就是 Serverless 服务的模型。
基本架构
Serverless 架构由两部分组成,即 Faas 和 BaaS。
Faas
FaaS(Function-as-a-Service)即为函数运行平台,用户无需搭建庞大的服务系统,只需要上传自己的逻辑函数如一些定时任务、数据处理任务等到云函数平台,配置执行条件触发器、路由等等,完成基础函数的注册。
Faas 运行函数的容器是无状态的,上一次的运行效果和下一次的运行效果是无关的。如果需要存储状态,则需要使用云储存或者云数据库。
Faas 函数如果长时间未使用,容器就会对其进行回收。所以函数在首次调用或长时间未使用时,容器就需要重新创建该函数的实例,这个过程称为冷启动,一般耗时为数百毫秒。
Faas是通过事件驱动的,当一个任务被触发时,比如 HTTP 请求,API Gateway 接受请求、解析和认证,传递对应参数给云函数平台,平台中执行对应回调函数,配合 DB、MQ 等 BaaS 服务在特定容器中完成计算,最终将结果返回给用户。函数执行完成后,一般会被 FaaS 平台销毁,释放对应容器,等待下一个函数运行。
既然有冷启动,就有热启动。例如容器刚刚调用完函数,过一会又有新的事件触发。这时由于函数仍未被回收,所以可以直接复用原有的函数实例,这被称为热启动。
Faas 如果单独使用的话,那它只适合部署一些工具类函数。因为它是无状态的,每次运行都可能是在不同的容器上,它不知道上一个函数的运行结果。所以如果要使用 Serverless 来部署整个应用,还得额外购买 OSS 云存储或者云数据库来提供数据存储服务(也就是需要配合 Baas 来使用)。
Baas
BaaS(Backend-as-a-Service)包含了后端服务组件,它是基于 API 的第三方服务,用于实现应用程序中的核心功能,包含常用的数据库、对象存储、消息队列、日志服务等等
Faas与Baas
Faas 其实是一个云计算平台,用户可以将自己写的函数托管到平台上运行。而 Baas 则是提供一系列的服务给用户运用,用户通过 API 调用。
其他不同点:
- Faas 无状态,Baas 有状态。
- Faas 运行的是函数,由开发者自己编写;Baas 提供的是服务,不需要开发者自己开发。
可以说 Faas 和 Baas 是两个不同的东西,但它们有一个共同点,就是无需自己管理服务器和资源的分配、整理,所以都属于 Serverless。
应用场景
Serverless 其实是通过事件驱动的,当一个任务被触发时,比如 HTTP 请求,API Gateway 接受请求、解析和认证,传递对应参数给云函数平台,平台中执行对应回调函数,配合 DB、MQ 等 BaaS 服务在特定容器中完成计算,最终将结果返回给用户。函数执行完成后,一般会被 FaaS 平台销毁,释放对应容器,等待下一个函数运行。
优缺点
优点
Serverless 最大的优点就是自动扩展伸缩、无需自己管理。
在以往部署一个应用时,需要经历购买服务器、安装操作系统、购买域名等等一系列步骤,应用才能真正的上线。后来有了云服务器,我们就省去了购买服务器、安装操作系统这些操作步骤。只需要在云服务器上搭建环境、安装数据库就可以部署应用了。
但是这仍然有个问题,当网站访问量过大时,你需要增加服务器;访问量过小时,需要减少服务器。如果使用 Serverless,你就不需要考虑这些,云服务商会帮你管理这一切。云服务商会根据你的访问量自动调整所需的资源。
缺点
当应用部署在云上,并且使用云存储或云数据库,那可能会让我们的应用访问速度变得比较慢。因为网络的访问速度比内存和硬盘差了一到两个数量级。
灰度发布/蓝绿部署/滚动发布
在一般情况下,升级服务器端应用,需要将应用源码或程序包上传到服务器,然后停止掉老版本服务,再启动新版本。但是这种简单的发布方式存在两个问题,一方面,在新版本升级过程中,服务是暂时中断的,另一方面,如果新版本有 BUG,升级失败,回滚起来也非常麻烦,容易造成更长时间的服务不可用。
蓝绿部署
所谓蓝绿部署,是指同时运行两个版本的应用,蓝绿部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上。但是蓝绿部署要求在升级过程中,同时运行两套程序,对硬件的要求就是日常所需的二倍,比如日常运行时,需要 10 台服务器支撑业务,那么使用蓝绿部署,你就需要购置二十台服务器。
滚动发布
所谓滚动升级,就是在升级过程中,并不一下子启动所有新版本,是先启动一台新版本,再停止一台老版本,然后再启动一台新版本,再停止一台老版本,直到升级完成,这样的话,如果日常需要 10 台服务器,那么升级过程中也就只需要 11 台就行了。
但是滚动升级有一个问题,在开始滚动升级后,流量会直接流向已经启动起来的新版本,但是这个时候,新版本是不一定可用的,比如需要进一步的测试才能确认。那么在滚动升级期间,整个系统就处于非常不稳定的状态,如果发现了问题,也比较难以确定是新版本还是老版本造成的问题。
为了解决这个问题,我们需要为滚动升级实现流量控制能力。
灰度发布
灰度发布(又名金丝雀发布,起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高)是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。
灰度期:灰度发布开始到结束期间的这一段时间,称为灰度期。
在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的 A/B 测试。
当确认新版本运行良好后,再逐步将更多的流量导入到新版本上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。直到将 100% 的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。
如果在灰度发布过程中(灰度期)发现了新版本有问题,就应该立即将流量切回老版本上,这样,就会将负面影响控制在最小范围内
总结
在新版本应用发布时,为了服务器不停机升级,使用灰度发布策略,在灰度发布开始时,使用 HTTP Header 匹配指定测试人员的流量到新版本上,然后当新版本内部测试通过后,可以再按百分比,将用户流量一点一点导入到新版本中,比如先导入 10% 观察一下运行情况,然后再导入 20%,如此累加,直到将流量全部导入到新版本上,最后完成升级,如果期间发现问题,就立即取消升级,将流量切回到老版本。
运用灰度发布,就再也不需要加班到深夜进行停机升级了,在白天就可以放心大胆地、安全地发布新版本
AB测试
单元测试
测试是保证代码质量的重要环节,web项目的单元测试虽然不能完全完成功能测试,但是却能保证底层单一模块的工作质量,并且在代码重构的时候保证对外接口不会发生变化。
经常会提到的敏捷开发,单元测试就是其中必不可少的一步。因此单元测试的需要,尤其是自动化单元测试不可忽略,而且应当作为整个团队的关键责任-而不仅仅是软件开发人员的责任。
- 单元:相对独立功能模块,类、模块、方法。
- 又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。
- 用来检验程式的内部逻辑,也称为个体测试、结构测试或逻辑驱动测试。
单元测试的重要性
由于存在浏览器解析环境、用户操作习惯等差异,前端程序的许多问题是无法捕捉或重现的,现在前端程序的测试多是黑盒测试,即靠点击点击点击来寻找程序bug。这种方式既费时费力,又无法保证测试的覆盖面。同时,前端逻辑和交互越来越复杂,和其他编程语言一样,一个函数,一个模块,在修改bug或添加新功能的过程中,很容易就产生新的bug,或使老的bug复活。这种情况下,反复进行黑盒测试,其工作量和测试质量是可想而知的。
- 反正都要手动测试,所以不如代码自动化。
- 为了实现依赖接口编程,大型软件项目多人合作时必须要有的
- 首先,得让你的代码能够测试
- 增强代码自信
黑盒测试
- bug无法捕捉、重现
- 费力,工作量大
- 覆盖面低
- 反复出现bug
单元测试
- 并不是所有的 js 都需要单元测试。中大型项目
- 并不是所有的 js 都能够单元测试。良好的模块化和解耦
TDD与BDD、相关概念
TDD:测试驱动开发(Test-Driven Development)测试驱动开发是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。TDD首先考虑使用需求(对象、功能、过程、接口等),主要是编写测试用例框架对功能的过程和接口进行设计,而测试框架可以持续进行验证。
BDD:行为驱动开发(Behavior Driven Development)行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。主要是从用户的需求出发,强调系统行为。BDD最初是由Dan North在2003年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。
测试套件”(test suite):describe (moduleName, testDetails)。可以嵌套使用,明白、易懂即可。describe块称为”测试套件”(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称(”加法函数的测试”),第二个参数是一个实际执行的函数。
测试用例”(test case):it (info, function)。具体的测试语句,可多个。it块称为”测试用例”(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称(”1 加 1 应该等于 2”),第二个参数是一个实际执行的函数。
- info,写期望的正确输出的简要一句话文字说明。info:当该it 的block内的test failed的时候控制台就会把详细信息打印出来。
- 测试用例之中,只要有一个断言为false,这个测试用例就会失败,只有所有断言都为true,测试用例才会通过。
- function,具体测试函数,一个测试用例内部,包含一个或多个断言(assert)。
断言指的是对代码行为的预期,会返回一个布尔值,表示代码行为是否符合预期。
- 所有的测试用例(it块)都应该含有一句或多句的断言。
- 断言是编写测试用例的关键
- 断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。
- 断言库有很多种,Mocha并不限制使用哪一种。
单元测试生命周期
每个测试块(describe)有4个周期函数:before、beforeEach、afterEach、after
| 周期函数 | 存在周期 | 主要功能 |
|---|---|---|
| before() | 在本区块的所有测试用例之前执行 | 用于同一的桩数据导入等功能 |
| beforeEach() | 在本区块的每个测试用例之前执行 | 用于清理测试环境,删除或回滚相关数据 |
| afterEach() | 在本区块的每个测试用例之后执行 | 可以用于准备测试用例所需的前置条件 |
| after() | 在本区块的所有测试用例之后执行 | 可以用于准备测试用例所需的后置条件 |
测试用例结构:
a. Setup: 准备好环境和数据,跑这个测试用例之前的准备
b. Execution:执行测试(测试用例的实现的主要代码)
c. Validation:验证结果
d. Cleanup:现场恢复,一般与a相反。不影响跑后面的测试用例。
TDD相关接口:
suite:定义一组测试用例。
suiteSetup:此方法会在这个suite所有测试用例执行前执行一次,只一次,这是跟setup的区别。
setup:此方法会在每个测试用例执行前都执行一遍。
test:具体执行的测试用例实现代码。
teardown:此方法会在每个测试用例执行后都执行一遍,与setup相反。
suiteTeardown:此方法会在这个suite所有测试用例执行后执行一次,与suiteSetup相反。
前端单元测试框架
前端测试框架有
- Mocha
- Jasmine
- Jest
- Tape
- Karma
Mocha
1 | npm install mocha --save-dev |
1 | const add = require("./add"); |
断言库
Mocha 支持should.js, chai, expect.js, better-assert, unexpected等断言库
1 | //assert |
should.js和expect.js相较于assert语义性更强,且支持类型检测,而should.js在语法上更加简明,同时支持链式语法.and。
- chai.js断言库:接口丰富,文档齐全,可以对各种接口进行断言。
- expect 库应用是非常广泛,拥有很好的链式结构和仿自然语言的方法。
- 通常写同一个断言会有几个方法,比如:expect(response).to.be(true) 和 expect(response).equal(true)。
expect和should是BDD风格的,二者使用相同的链式语言来组织断言,但不同在于他们初始化断言的方式:expect使用构造函数来创建断言对象实例,而should通过为Object.prototype新增方法来实现断言(所以should不支持IE);expect直接指向chai.expect,而should则是chai.should()。
expect断言风格
- ok :检查是否为真
- true:检查对象是否为真
- to.be、to:作为连接两个方法的链式方法
- not:链接一个否定的断言,如 expect(false).not.to.be(true)
- a/an:检查类型(也适用于数组类型)
- include/contain:检查数组或字符串是否包含某个元素
- below/above:检查是否大于或者小于某个限定值
assert风格是三种断言风格中唯一不支持链式调用的,Chai提供的assert风格的断言和node.js包含的assert模块非常相似。
Mocha 支持4种 hook,包括before / after / beforeEach / afterEach。
Mocha 默认每个测试用例执行2000ms,超出时长则报错,所以在测试代码中如果有异步操作,则需要通过done函数来明确测试用例结束。done接受Error参数。
Mocha 在node环境下运行时,不支持 BOM 和 DOM 接口,需要引入jsdom和jsdom-global库。
Mocha命令行基本用法:
- mocha:默认运行test子目录里面的测试脚本,不包括子文件
- mocha add.test.js:当前目录下面的该测试脚本。
- mocha file1 file2 file3 : mocha命令后面紧跟测试脚本的路径和文件名,可以指定多个测试用例。
通配符:
- mocha spec/{my,awesome}.js
- mocha test/unit/*.js
生成格式
- mocha –reporter spec:默认为spec格式,可设置其他格式。
- mocha –recursive -R markdown > spec.md 。
网页查看
npm install –save-dev mochawesome
在gulp中运行mocha
安装gulp-mocha插件
1 | npm install gulp-mocha --save-dev |
gulpfile
1 | gulp.task('mocha',function() { |
Jasmine
Jasmine 是一个功能全面的测试框架,内置断言expect;但是有全局声明,且需要配置,相对来说使用更复杂、不够灵活。
1 | npm install jasmine --save-dev |
Jasmine 的语法与 Mocha 非常相似,不过断言采用内置的expect()。
Jest
Jest 是一个功能全面的“零配置”测试框架,既集成了各种工具,且无需配置即可使用。
1 | npm install --save-dev jest |
Jest 中以test定义一个测试用例,且自带断言expect,断言库功能强大,但语法相较于should.js来说更复杂。
普通匹配:toBe, not.toBe
空匹配:toBeNull, toBeUndefined, toBeDefine, toBeTruthy, toBeFalsy
数字大小:toBeGreaterThan, toBeGreaterThanOrEqual, toBeLessThan, toEqual, toBeCloseTo(用于浮点数)
正则匹配:toMatch
数组查询:toContain
构造匹配:toEqual(expect.any(constructor))
Jest 同样有四个hook,beforeAll/beforeEach/afterAll/afterEach
Jest 内置对 DOM 和 BOM 接口的支持。
Jest 内置覆盖统计,为了更方便地进行相关配置,我们可以创建一个配置文件jest.config.js
然后将package.json中的命名修改一下:"test-jest": "jest"
jest教程:http://github.yanhaixiang.com/jest-tutorial/#%E6%B5%8B%E8%AF%95%E9%9A%BE%E7%82%B9
Vitest
单元测试与集成测试、功能测试
三种测试的主要作用
- 单元测试,单个组件正常工作,开发阶段;用来确保每个组件正常工作 —— 测试组件的 API 。
- 集成测试,不同组件互相合作,中间阶段;用来确保不同组件互相合作 —— 测试组件的 API, UI, 或者边缘情况(比如数据库I/O,登录等等)。
- 功能测试,主要测试界面,开发完成。 用来确保整个应用会按照用户期望的那样运行 —— 主要测试界面
三种测试在不同阶段的重要性
- 开发阶段,主要是程序员反馈。这时单元测试很有用。
- 在中间阶段,主要是能够在发现问题时立刻停下来。这时各种测试都很有用。
- 在生产环境,主要是运行功能测试套件,确保部署的时候没有弄坏什么东西。
DDD驱动测试
e2e测试
接口工具
互联网公司常用的接口文档管理平台
Swagger
Swagger是一个大型的API开发者的工具框架,该框架提出了一个编写OpenAPI的规范(命名为OAS),并且Swagger可以跨整个API生命周期进行开发,从设计和文档到测试和部署。 Swagger框架三核心:
- 提供了一个编写API文档的规范 ,称为OAS ,在规范中明确API的格式和一些编写要素;
- 提供相关的工具,对API文档的编写提供辅助。主要是这么几个项目 Swagger Editor、SwaggerUI、Swagger Codegen、Swagger Inspector;
- 提供对各种流行语言和框架的集成,例如集成SpringMVC 的 springfox 框架;
Yapi
YApi 是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。它可以帮助开发者轻松创建、发布、以及维护API。除此之外,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。特性:
- 基于 Json5 和 Mockjs 定义接口返回数据的结构和文档,效率提升多倍
- 扁平化权限设计,即保证了大型企业级项目的管理,又保证了易用性
- 类似 postman 的接口调试
- 自动化测试, 支持对 Response 断言
- MockServer 除支持普通的随机 mock 外,还增加了 Mock 期望功能,根据设置的请求过滤规则,返回期望数据
- 支持 postman, har, swagger 数据导入
- 免费开源,内网部署,信息再也不怕泄露了。
Eolinker
Eolinker是国内企业级IT研发管理解决方案服务品牌,在线API接口管理服务供应商,致力于满足各行业客户在不同应用环境中对研发管理全生命周期的个性化需求,提供API开发管理(AMS)、开发团队协作、自动化测试、网关(AGW)以及监控(AMT)等服务。 特性:
- 接口信息的录入与导出
- 在线测试
- 团队协作管理
- 支持数据字典的录入
- 用户常用到的小工具
- 对状态码进行管理
ShowDoc
ShowDoc一个非常适合IT团队的在线API文档、技术文档工具。 随着移动互联网的发展,BaaS(后端即服务)越来越流行。服务端提供API,APP端或者网页前端便可方便调用数据。用ShowDoc可以非常方便快速地编写出美观的API文档。
DOClever接口管理工具
DOClever是一个可视化接口管理工具 ,可以分析接口结构,校验接口正确性, 围绕接口定义文档,通过一系列自动化工具提升我们的协作效率。 特性:
- 1 接口快照回滚,项目版本控制
- 2 兼容最新版Swagger,PostMan等平台数据
- 3 接口文档自动在线生成
- 4 Restful,Query,Header,Body,Raw信息一应俱全,独有的proxy技术加持为您冲破内网的束缚
RAP2接口管理工具
阿里妈妈前端团队出品的开源接口管理工具RAP第二代,RAP通过GUI工具帮助WEB工程师更高效的管理接口文档,同时通过分析接口结构自动生成Mock数据、校验真实接口的正确性,使接口文档成为开发流程中的强依赖。有了结构化的API数据,RAP可以做的更多,而我们可以避免更多重复劳动。基于RAML的接口定义、文档生成、Mock Server完成了定义和使用的分离,通过一套规范完成的接口定义,可以用不同的工具得到适应不同API管理系统的输出,有更多的可能性,同时保持了核心定义不变。RAP较之于RAML,前者更加集中,所有的定义、文档、mock都在同一个服务中完成,并且实时生效,方便快捷,如果只考虑方便易用,RAP是更好的选择,而RAML显得更加繁琐,更适合于公开的接口定义,方便在各个系统之间流转。
Apifox
https://zhuanlan.zhihu.com/p/140802042
npm私库搭建
1 | npm install --globale verdaccio |
前端CDN资源
表情/ICON资源
表情包资源:https://app.streamlinehq.com/emojis/kawaii-emoji
前端bundleless
随着业务的发展,前端代码的复杂度越来越高,构建方面展露新的问题:
过去需要打包的原因:
1.http1.1各浏览器有并行连接限制
2.浏览器不支持模块系统(如commonjs不能在浏览器直接运行)
3.代码依赖关系与顺序管理
可以开始不打包的原因:
1.http2.0多路并用
2.各大浏览器逐一支持ESM
3.越来越多的npm包拥抱ESM(尽管还有很多包不是)
目前构建主要分为两种:
1是基于服务的构建方式。通常服务于实际生产。可以再细分成本地服务构建与远端服务构建。本地服务构建就是我们常规的操作,基本被webpack统治,是bundle方案的代表,snowpack、Vite、Web Dev Server是目前比较火的Bundleless方案,发展迅猛。远端服务构建则是依托云能力的玩法,把构建过程放在服务端完成。
2是基于浏览器的构建方式。通常面向Demo的快速搭建或预览方案。Codesandbox、StackBlitz、CodePen和Riddel是业内比较出色的方案。整体是在浏览器端实现代码的编译、打包、构建和运行。
重构
原则
- 事不过三,三则重构。即不能重复写同样的代码,在这种情况下要去重构。
- 如果一段代码让人很难看懂,那就该考虑重构了。
- 如果已经理解了代码,但是非常繁琐或者不够好,也可以重构。
- 过长的函数,需要重构。
- 一个函数最好对应一个功能,如果一个函数被塞入多个功能,那就要对它进行重构了。(4 和 5 不冲突)
- 重构的关键在于运用大量微小且保持软件行为的步骤,一步步达成大规模的修改。每个单独的重构要么很小,要么由若干小步骤组合而成。
手段:
- 提取重复代码,封装成函数
- 拆分功能太多的函数
- 变量/函数改名
- 替换算法
- 以函数调用取代内联代码
- 移动语句
- 折分嵌套条件表达式
- 将查询函数和修改函数分离

