《前端技术架构与工程》之编程语言笔记

《前端技术架构与工程》之编程语言

前言:昨天写了部分这本书的笔记,今天把剩下的写一写。共分为三部分笔记。一次讲绪论、一次讲技术架构、一次讲工程服务体系。

《前端技术架构与工程》初次笔记

接下来讲技术架构部分(编程语言、技术规范、组件化、前后端分离、性能)其中的编程语言。

不会按照书本上的内容照抄,不然好没意思,除非非常必要,一般用自己的理解解释。

不过这本书好多东西我都想写上来,书上的内容就是我想要了解的。会有许多篇幅是来自原文的。只能说都是精华。

第一部分我会着重书写~~,后面的我只搭建一个框架,具体细节我做笔记在书上,再敲到这博客里好麻烦。~~

每一部分都很精华,还是按照每一章来写,技术架构这一部分不好一次性讲完。

前情回顾

软件架构

软件架构和软件工程的概念是有区别的。架构强调的是强调软件系统的设计方法论和实施模式,具体到做一个网站的时候,架构师做的是一个组长的角色,做的工作是把框架搭好,组织其他人员做架构以内的细节部分 ,如前端、后端、测试、运维。

工程学的核心是结合实际情况建立科学的、规范的设计和生产流程,降低生产成本,把这理念带入软件开发领域便形成了软件工程。

这本书的核心:以业务为出发点,架构聚焦于代码,工程聚焦于流程。

代码和流程是软件工程的核心关注点。从代码的角度考虑,工程的模板是保证软件的高可用性、可扩展性、可伸缩性、性能以及安全,这些要素共用组成了软件的技术架构;在架构之外,工程从更宏观的角度完善开发和运维流程的管控,强调项目迭代的规范性、有序性、可控性和高效性,并更加架构特征提供额外的辅助功能,也就是说,架构是工程的子集,其关系是(工程(架构(业务)))。

为了便于区分和理解,本书将前端工程化中架构之外的部分称为前端工程服务体系。如此得出前端工程化的定义:前端工程化=前端技术架构+前端工程服务体系。

开发Dev与运维Ops

在前几年,许多公司在技术团队的组织架构划分秉承研发与运维分离的原则,即负责业务设计(产品经理、设计师)、开发(工程师)、测试(测试员)的岗位组成应用研发团队,而负责部署和发布(运维师)的岗位独立为线上保障团队。

项目经过需求设计、交互设计、开发以及测试后,开发人员将项目代码递交给运维人员,递交方式是将压缩包通过QQ或邮件直接交付。运维人员收到代码的时候将项目文件进行部署和发布,同时还负责服务器预警处理以及版本回滚。

将开放与运维分离的目的是保证线上的稳定性,开发人员不直接接触生产环境,可以减少很多人为失误导致的低级错误。同时可以建立固定的上线周期。但是缺点是影响迭代的自由度。

故DevOps模式开始崛起,目标是实现软件开发、测试和发布的敏捷性和持续化。

前端架构师的职责

根据前面对前端工程化的定义,前端架构师的职责可以概括为两方面:

根据业务特征设计合理的前端技术架构。
根据架构特征搭建高效的前端工程服务体系
这本书的核心:以业务为出发点,架构聚焦于代码,工程聚焦于流程。

技术架构方面从五个部分讲:编程语言、技术规范、组件化、前后端分离、性能;

工程服务体系方面从五方面将:开发、构建、测试、部署、持续化、监控与统计;

成本控制(时间成本、生产成本)是工程的核心关注点。具体到实际工作中,成本细分为人力成本和沟通成本。前端工程服务体系的目标是:降低开发本身所消耗的人力成本;降低跨团队协作消耗的沟通成本。

编程语言

这一章对HTM、CSS、JavaScript的内容进行了架构角度的理解。

HTML部分讲了客户端渲染CSR和服务端渲染SSR将了其各自的概念以及优缺点。其中CSR部分点到的virtual DOM、预处理、SEO十分恰到好处,切入点精彩。

CSS部分讲了CSS预处理。

JavaScript部分讲了异步编程的方案选择。

开发iOS可以选择swift、开发安卓应用可以选择Java、kotlin,服务端编程语言可以选择PHP、Java、go,而前端语言始终只要HTML、CSS、JavaScript,未来WebAssembly的进一步完善和普及能给前端带来更丰富的编程语言选择。

技术栈单一的好处是初学者有明确的学习方向,不必像其他领域的开发者一样纠结编程语言的选择;缺点是长期使用固定的编程语言很容易令开发者形成思维定式,缺乏跨领域思考和解决问题的能力。技术演变与架构设计不仅以本领域技术栈的特征为基础,同时也需要在其他领域摄取灵感,比如Vue等流行前端框架所采用的MVVM架构模式便借鉴自WPF。

HTML

web网站诞生到发展至今的二十几年时间里,用JavaScript编写HTML和CSS的趋势越来越明显。如Vue等开发框架。

web网站从静态的webpage到动态webapp的过程中,客户端渲染和服务端渲染占了其中浓墨重彩的一部分。HTML渲染是前后端耦合最紧密的环节,客户端渲染和服务端渲染是两种基本模式。

相对而言,服务端渲染SSR有更深的技术沉淀和产业生态,但是客户端渲染更有利于前后端分离。在实际开发中,不同渲染模式适用于不同特征的业务。

SSR

在服务器端渲染,相比而言,其主要优势在于其支持SEO且首屏时间短,前者从web整体产业生态出发,后者从用户体验出发。SSR适用于交互简单、以静态内容为主并且有SEO需求的业务产品。

传统模块引擎:传统SSR的实现模式是借助于服务端编程语言或框架搭配的HTML模块引擎将数据编译为HTML文档。如Java的freemarker、PHP的smarty、node.js的pug。模块引擎可以理解为一个功能强大的字符串处理工厂,最大的优势是快速和缓存。

react/vue SSR:virtual DOM令前端脱离对浏览器环境的强依赖,使用React/Vue承担SSR的主要优势是同构编程,同一组件可以同时适用于客户端和服务端,但缺点是目前性能差。

CSR

在客户端渲染,其优势是更好地支持离线场景和前后端分离方案的实施,劣势是弱SEO且首屏时间长。导致首屏渲染时间长的原因是服务器的配置通常优于个人电脑,同时搭配模块引擎的缓存功能,但随着个人电脑硬件性能的不断提示、网络传输、浏览器性能的提升,这些劣势也逐渐缩小;而SEO也可以通过技术慢慢提示。

virtual DOM

虚拟DOM大幅度提升了对修改HTML元素的性能,使网页响应更快。

DOM储存于内存中,提供操作和修改HTML元素的一系列API。DOM操作是前端开发的核心,最早流行的前端框架都以优秀的DOM操作闻名,如jQuery。与JavaScript逻辑相比,DOM操作的性能消耗非常高,在以静态内容为主的webpage时代,少量DOM操作的性能损耗基本可以忽略,然而对于存在丰富动态内容的webapp而言,大量、频繁的DOM操作逐渐成为了性能瓶颈。

virtual DOM技术的核心是创建DOM对象的一个轻量级克隆对象,虚拟DOM拥有原始DOM除了操作HTML元素的API以外的所有属性。对于JavaScript而言,虚拟DOM仅仅是一个拥有丰富属性的对象,所有针对DOM的操作被映射为对JavaScript对象的修改,性能上大幅度优于直接对DOM的操作。在接收到动态数据或用户操作后,Vue或react会在内存中将虚拟DOM树全量更新,对比检查受影响的对象,随后对这些对象所对应的真实DOM进行对应修改。得益于Vue或react的diff算法,可以采用全量更新策略并且能够保障对比性能。

预渲染

预渲染从交互设计的角度上使网页响应更友善。

用户从输入网站地址按下回车键到能够在浏览器中有内容输出,这段时间被称为首屏的白屏时间。除去DNS查找、TCP握手等开发者无法干预的浏览器前期工作外,SSR的白屏时间之所以相对短的原因是HTML文档的HTTP请求响应内容有真实内容,渲染即可见。而由于浏览器解析

解决方法就是预先渲染出页面骨架来代替空白的加载页面,让用户能够优先得到视觉上的反馈,从而一定程度上减少用户耐心的 消耗。

SEO

SPA如何支持SEO是前端领域这几年的热门话题,目前普遍的弥补方案大致分为两类。具体看原书。

第一种方案是预渲染静态内容,在构建阶段将内容提前解析为HTML字符串并添加到index.html中,目前主流的构建工具都提供预渲染功能,如webpack。优点在于实施成本较低,不涉及服务端开发,但对存在大量路由和动态数据的SPA项目,其对SEO提升小。

第二种方案是由仿真浏览器环境代替模板引擎,优点是媲美SSR的SEO支持,缺点是部署成本高。

CSS

CSS是一门非常简单同时非常难的语言,它上手非常容易,就像HTML的配置选项,新手参照手册可以快速配置出不错的UI效果。但是CSS没有变量、没有命名空间、缺乏计算能力,造成CSS无规律可循,实现方案多样、难以复用的问题。

CSS的不足

1没有任何报错机制。浏览器解析CSS代码只会忽略错误代码,不会抛出任何可见的错误,检查错误时,不便解决错误;

2没有命名空间。CSS规则应用于符合CSS选择器规则的所有元素,后续迭代中,难以拓展;

3兼容性。由于各浏览器对CSS规范的支持程度不一,为了兼容多个浏览器,大量兼容性的代码令CSS文件越来越冗余,增加了开发和维护难度,还拖累了web性能;

4低复用性。这是非常关键的一点。

CSS预处理

CSS预处理是目前被广泛应用的CSS开发模式之一。less可视为是一个具备特殊语法规范、可编译为CSS的开发框架。它弥补了CSS逻辑处理和复用性的不足,引入变量、混合、模块、继承等特性,同时支持更易于编写和维护的嵌套语法,从细节和整体上提升了CSS的开发和维护效率。

不过缺点是大而全,容易导致代码规范难以约束;难扩展,核心架构过于封闭,缺失插件生态。

CSS in JS

在JavaScript中编写CSS代码不是新鲜概念,在jQuery早期版本中提供相关API就可以实现。但CSS in JavaScript的核心不是简单在JavaScript中编写CSS代码,而是利用JavaScript的语言特性和技术生态弥补CSS开发 模式的不足。

模块。将JavaScript的模块体系带入CSS开发领域可以有效弥补CSS模块体系的不足;

命名空间。CSS in JSt将组件以及内部元素的样式限制在唯一的命名空间,从而实现样式的隔离;

动态性。CSS in JS有样式规则与JavaScript逻辑的互操作性。

JavaScript

前端发展的功能大部分来自JavaScript语言的推到。基于浏览器与JavaScript捆绑销售的现状,前端语言的选择单一。不过JavaScript十分灵活,开发者进行技术选型的时候有丰富的框架、工具和规范可供参考。

编程风格极具个人色彩,虽然编程风格没有好坏之分,但是多样的编程风格对团队和产品是一种灾难。JavaScript的灵活性体现在语言本身的多样性和实现方案的多样性,针对这两点,有两种约束途径:技术选型、代码规范。

统一的技术栈是基础,在此之上才能统一代码规范。技术栈又细分为底层技术栈和实现层技术栈。比如针对一个复杂的CMS进行技术选型时,使用TypeScript为JavaScript编程加入静态类型属于底层技术栈,它们解决了语言层次的问题,然后使用vue同时搭配babel/webpack等工具则属于实现层技术栈。在JavaScript编程领域,静态类型static types和数据不可变性是目前底层技术栈要解决的两个主要问题。

代码规范可以细分为代码风格和方案选择。代码风格与逻辑无关,大都可以用ESLint等工具进行检查和校正。方案选择指一种逻辑可以用多种方案实现,如何选择最合理的方案,如JavaScript异步编程,是选择常规的回调函数还是promise,在promise的基础上使用generator还是async/await。在任何一种方案的基础上都可以通过合理地进行封装实现健壮的架构,如接着babel可以在源码开发阶段使用浏览器尚不支持的JavaScript未来特性和语法。实现方案代码的正确性和合理性无法完全使用工具检测,人工审查必不可少。

静态类型

JavaScript是一种动态类型语言,开发者在声明变量时无需指明变量类型,解释器会根据赋值判断其类型。动态类型能够很大程度增强语言的灵活性和提高开发效率,对轻量级项目有绝对积极的作用,但涉及大型项目需要警惕动态类型的负面效应。

由动态类型引起的bug对于前端应用不是少数,甚至超过了逻辑上的bug,而且这些bug大多数在测试或生产环境中暴露出来,对产品的稳定性造成巨大威胁。为JavaScript引入静态类型的目的便是将与类型有关的bug提前在编译阶段暴露出来,借助一下支持语法检查的IDE甚至在开发阶段便可解决隐患。

除了提前检测出bug外,静态类型还能够增强代码的语义性和易读性,在一定程度简化逻辑,并且更有利於单元测试。

JavaScript基础类型是静态类型体系最初级的部分,此外还有枚举Enum、接口interface、泛型generic等。这些需要长时间的学习,初期学到的静态类型代码可能还不如动态类型代码健壮,这些需要大量的使用。

TypeSript是目前流行的JavaScript静态类型编程工具,是JavaScript的超集,是一种编译型编程语言,本质上与coffeescript相同。

不可变性

JavaScript的不可变性兴起于redux的流行,在状态管理这种特定场景下,不可变性令数据可预测、可追踪,并且可以实现类似时光回流的效果。

除了不可变性,redux还采取了函数式编程。函数式编程历史久远于面向对象编程,但确实JavaScript编程领域一直未普及的编程方式。函数式编程强调数据的不可变性,在状态管理这种特定场景下,函数式编程与数据不可变性的结合十分适用。

异步编程

在深入JavaScript异步编程技术之前,有必要对调用栈、堆、任务队列、事件循环进行解释。

调用栈call stack:是一种类数组的结构,用于跟踪函数的调用。

堆heap:是一种无序、散列的结构,用于存储对象。

任务队列task queue:JavaScript引擎用于存储任务的一个有序队列。

事件循环Event Loop:用上述理论基础理解Event Loop的运行机制就是Event Loop检测调用栈为空闲状态时将回调函数加入任务队列中并且执行。在此基础上对JavaScript单线程的解读是:JavaScript只存在一个任务队列,队列中的任务按照被加入队列的顺序被依次执行。

JavaScript异步编程的基本原理是得到(ajax或HTTP)请求后通知JavaScript引擎,Event Loop检测调用栈为空闲状态时将回调函数加入任务队列中并且执行。

无论回调函数、promise、async/await都是在此基础上的具象封装。promise解决了回调函数的回调地狱问题,但是会产生新的then hell问题。这两者都是相对底层的异步编程模式,通常需要额外的封装才能有效地提高开发效率。目前JavaScript在语言层面较上层的异步编程模式是async/await。得益于babel和polyfill(用于编写下一代JavaScript的编译器),这种编程模式可以应用于实际开发中。

总结

前端编程语言虽然单一但是具有高度的灵活性,所以从语言层面和架构模式层面都需要细细打磨。

HTML渲染是前后端耦合最紧密的环境,服务端渲染和客户端渲染是两种基本模式。相对而言,SSR有更深的技术沉淀和产业生态,CSR更有利于前后端分离。在实际开发中,不同的渲染模式适用于不同特征的业务。我的话,为了前后端分离,以SSR为基础,去学习和应用CSR。

CSS的弱编程能力给开发和维护带来了极大的挑战。为了兼容性、可复用性,我先初期学习less和CSS in JavaScript。PostCSS和Houdini等需要用的时候用。

为JavaScript加入静态类型能够有效地开发或编译阶段消除一下由动态类型产生的隐患,对于复杂架构系统非常有必要。数据的不可变性和函数式编程有天然的融合性,两者结合能够很大程度上提高JavaScript代码的可测试性。从技术选型和代码规范上学习静态类型、数据不可变性、ESLint、异步编程。提前处理由动态类型引起的bug,使得编写的程序更稳健。在这里可以解决Java语言。

最后,本来是想写自己的理解,却没想到这里许多内容都感觉有必要写出来。大家如果感兴趣的话,亲自看书体验更佳。

更新地址:GitHub

更多内容请关注:CSDNGitHub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章