大前端公共知识杂谈首发于InfoQ-架构师特刊:大前端,是笔者对于泛前端知识图谱(Web/iOS/Android/RN) 的文字版介绍,夹杂了 GUI 应用程序架构的十年变迁:MVC、MVP、MVVM、Unidirectional、Clean 的部份内容;更多参考资料能够查看笔者的 Web 学习与实践资料索引以及 React 学习与实践资料索引。前端
近年来,随着移动化联网浪潮的汹涌而来与浏览器性能的提高,iOS、Android、Web 等前端开发技术各领风骚,大前端的概念也日渐成为某种共识。其中特别是 Web 开发的领域,以单页应用为表明的富客户端应用迅速流行,各类框架理念争妍斗艳,百花竞放。而 Web 技术的蓬勃发展也催生了一系列跨端混合开发技术,但愿可以结合 Web 的开发便捷性与原生应用的高性能性;其中以 Cordova、PWA 为表明的方向致力于为 Web 应用尽量添加原生体验,而以 NativeScript、ReactNative、Weex 为表明的利用 Web 技术或者理念开发原生应用。平心而论,不管哪种开发领域或者技术,他们本质上都是进行图形用户界面(GUI)应用程序的开发,面对的问题、思考的方式、架构的设计很大程度上仍然能够回溯到当年以 MFC、Swing、WPF 为主导的桌面应用程序开发时代,其术不一样而道类似。react
任何的前端开发学习中,咱们都须要掌握基本的编程语言语法与接口;譬如在 Android 开发中使用的 Java 或者 Kotlin,在 iOS 开发中使用的 Objective-C 或者 Swift,在 Web 开发中使用的 JavaScript、HTML 与 CSS 等。编程语言的学习中咱们每每关注于语法基础、数据结构、功能调用、泛型编程、元编程等内容,譬如如何声明表达式、如何理解做用域与闭包、如何进行基本的流程控制与异常处理、如何实践面向对象编程、如何进行网络请求通讯等等。接下来咱们就须要了解如何构建基础的界面,譬如利用 HTML 与 CSS 绘制简单 Web 页面、利用代码建立并使用简单的 Activity、利用 StoryBoard 快速构建界面原型等等。而后咱们须要去学习使用常见的系统功能,譬如如何进行网络交互,如何访问远端的 RESTful 接口以获取须要的数据、如何读取本地文件或者利用 SharedPreference、localStorage、CoreData 来存取数据、如何进行组件间或者应用间信息交互等内容。到这里咱们已经可以进行基础的界面开发,而且为其增添必要的特性,不过在真实的项目中咱们每每还会用到不少的组件或者插件,iOS 或者 Android 中为咱们提供了丰富的 SDK,譬如 UITableView 或者 RecycleView 能够帮助咱们快速构建高性能列表组件,Android 5.0 以后默认的 Material Design 也是很是优秀的界面样式设计指南;而 Web 开发中咱们每每须要引入第三方模式库,譬如著名的 BootStrap、React Material UI、Vue element 都为咱们提供了不少预置的样式组件,react-virtualized 也为咱们提供了高性能的相似于 ListView 这样的部分项渲染机制。而后咱们须要将应用真实地发布给用户使用,咱们须要考虑不少工程实践的问题,譬如如何进行测试与调试、如何进行性能优化而且在生产环境下完成应用状态跟踪、热更新等操做、如何统一开发团队的代码风格与约定等等;这里 Web 由于其特性而自带了热更新的功能,而在 Android 或者 iOS 咱们则能够利用插件化技术或者 JSPatch 来实现热更新。Java 与 Swift 都是强类型语言,其可以在编译阶段帮开发者排查问题减小潜在风险;而咱们也可使用 TypeScript 或者 Flow 为 JavaScript 添加静态类型检测的特性,在 VSCode 等现代编辑器中一样能够达到相似于 Android Studio、XCode 中的即时检查与提示的功能。最后,随着应用功能的增长、代码库的扩展,咱们须要考虑总体的应用架构与工程化的问题;在应用架构中咱们每每须要考虑模块化、组件化以及状态管理等多个方面,选择合适的 MVC、MVP、MVVM、Flux、VIPER 等不一样的架构模式来引导应用中的代码组织与职责分割;咱们也须要考虑选择合适的构建与部署工具来简化或者自动化应用发布流程,在 Android 开发中咱们会选择 Gradle 及其自带的多模块特性来管理依赖与分割代码,而在 Web 中咱们可使用 Webpack、Rollup 等工具来自动处理依赖而且进行构建,iOS 中咱们也能够选择 CoocaPods。程序员
到这里咱们会发现虽然具体的代码实现、使用的技术不一样,可是 Android、iOS 以及 Web 乃至于 React Native 等开发中,咱们须要解决的问题、可以用到的架构设计模式都是能够相互借鉴的。在咱们从某个领域迁移到其余领域时,咱们能很方便地知道应该学习些什么,不一样的技术、工具他们的职责是什么,应该选择怎样的架构或者设计模式。古语云,欲穷千里目,更上一层楼,咱们想要真正掌握某种客户端开发技术,最好是要了解咱们应该掌握哪些方面,本文便是对笔者日前总结出的泛前端知识图谱(Web/iOS/Android/RN) 的简要阐释。正则表达式
编程语言的学习是咱们进入软件世界的基础阶梯,著名的 Code Complete 一书中提到:Program into Your Language, Not in it. 咱们不该该将本身的编程思惟局限于掌握的语言提供的那些特性或者概念,而是可以理解这些语法特性背后能提供的抽象功能与原理,从而可以根据本身想要达到的目标选择最合适的编程语言。而从另外一个角度来看,不管哪一门编程语言的学习也是具备极大的共性,从严谨而又被诟病过分冗余的 Java 到须要用游标卡尺的 Python,从挣扎着一路向前的 JavaScript 到含着金汤勺出生的 Swift、Rust,咱们都可以发现其中的相通与互相借鉴之处。算法
任何一门编程语言的学习都须要从基本的表达式(Expression)语法开始学习,咱们须要了解如何去声明与使用变量、如何为这些变量赋值、如何使用运算符进行简单的变量操做等等。在不少语言之中都有所谓的传值仍是传引用的思量,譬如 Java 与 JavaScript 本质上就是 Pass-by-Value 的语言,只不过会将复杂对象的引用值传递给目标变量。这个特性又引起了所谓浅复制与深复制、如何进行复合类型深拷贝等等须要注意的技术点。除此以外,做用域与闭包也是不少语言学习中重点讨论的内容,在 JavaScript 与 Python 的学习中咱们就会常常讨论如何利用闭包来保存外部变量,或者在循环中避免闭包带来的意外变量值。表达式是一门编程语言语法基础的重要组成部分,接下来咱们就须要去学习流程控制与异常处理、函数定义与调用、类与对象、输入输出流、模块等内容。流程控制的典型表明就是分支选择与循环,譬如不一样的语言都为咱们提供了基础 for 循环或者更方便地 for-in 循环,而在 JavaScript 中咱们还可使用 forEach 与 for-of 循环,Java 8 以后咱们也能够基于 Stream API 中的 forEach 编写声明式地循环执行体,而 Python 中的列表推导也能够看作便捷的循环实现方式。异常处理也是各个编程语言的重要组成部分,合理的异常处理有助于加强应用的鲁棒性;不过不少时候会出现滥用异常的状况,咱们只是一层一层地抛出而并未真正地去处理或者利用这些异常。Java 中将异常分为了受控异常与不受控异常这两类,虽然 JavaScript 等语言中并未在数据类型中有所区分,可是却能够引入这种分类方式来进行不一样的异常处理;有时候 Let it Crash 也是不错的设计模式。数据库
Eric Elliott 曾在博文中说起,软件开发实际就是 Function Composition 与 DataStructure Design;函数或者方法是软件系统的重要基石与组成。咱们须要了解如何去定义函数,包括匿名函数以及 Lambda 表达式等;尽管 Java 中的 Lambda 表达式是对于 FunctionalInterface 的实现,可是鉴于其表现形式咱们也能够将其划归到函数这个知识类别中。接下来咱们须要了解如何定义与传入函数参数,在 C 这样的语言中咱们会去关心指针传递的不一样姿式;而在 JavaScript 中咱们经常会关心如何设置默认参数,不管是使用对象解构仍是可选参数,都各有利弊。Objective-C 与 Swift 中提供的外部参数就是不错的函数自描述,Java 或 Python 中提供的不定参数也可以帮咱们更灵活地定义参数,在 JavaScript 中咱们则能够经过扩展操做符实现相似的效果。而后咱们就须要去考虑如何调用函数,最典型就是就是 JavaScript 中函数调用的四种方式,咱们还须要去关心调用时函数内部的 this 指针指向。而装饰器或者注解能帮咱们更好地组织代码,以相似于高阶函数的方式如洋葱圈般一层一层地剥离与抽象业务逻辑。最后在函数这部分咱们还须要关心下迭代器与生成器,它们是不错的异步实现模式或者流数据构建工具。编程
近几年随着前端富客户端应用的迅猛发展与服务端并发编程的深刻应用,函数式编程以及 Haskell 这样的函数式编程语言也是引领风骚。尽管面向对象编程也有着不少其余被人诟病的地方,可是在大型复杂业务逻辑的应用开发中咱们仍是会倾向使用面向对象编程的范式;这就要求咱们对于类与对象的基本语法有所掌握。咱们首先要去了解如何定义类,定义类的属性、方法以及使用访问修饰符等方式进行访问控制。其次咱们须要了解如何从类中实例化出对象,如何在具体的语言中实践单例模式等。而后咱们就须要去了解面向对象的继承与多态的特性,应该如何实现类继承,子类与父类在静态属性、静态方法、类属性、构造函数上的调用顺序是怎样的;以及如何利用纯虚函数、抽象类、接口、协议这些不一样的关键字在具体语言中实现多态与约定。最后咱们还须要去关注下语言是否支持内部类,譬如 Java 就分为了静态内部类、成员内部类、局部内部类与匿名内部类这四种不一样的分类。在整个语法基础部分的最后,咱们还须要去了解下输入输出流与模块化相关的知识,譬如 Java 9 中即将推出 JPMS 模块化系统,而 JavaScript 的模块化标准则历经了 CommonJS、AMD、UMD、ES6 Modules 等多轮变迁。设计模式
语法基础是咱们掌握某门编程语言的敲门砖,而学习内建的数据结构与功能语法则是可以用该语言进行实际应用开发的重要前提。在数据结构的学习中咱们首先要对该语言内建的数据类型有所概览,咱们要了解如何进行常见的类型与值判断以及类型间转换;譬如如何进行引用与值的等价性判断、如何进行动态类型检查、如何对复合对象的经常使用属性进行判断等等。不少编程语言中会将数据类型划分为原始类型(Primitive)与复合类型(Composite),不过这里为了保证通用性仍是将学习复杂度较低的数据类型划归到基本类型中。常见的基本类型囊括了数值类型、空类型、布尔类型、可选类型(Optional)以及枚举类型(Enum)等等。学习数值类型的时候咱们还须要了解如何进行随机数生成、如何进行常见的科学计算,这也是基础的数值理论算法的重要组成。JavaScript 中提供了 undefined 与 null 两个关键字,两者均可以认为是空类型不过又有所区别;而可选类型则可以帮咱们更好地处理可能为空地对象,避免不少的运行时错误。接下来咱们就要将目光投注于字符串类型上,咱们须要了解如何建立、删除、复制、替换某个字符串或者其余内容;不少语言也提供了模板字符串或者格式化字符串的方式来建立新字符串。咱们还须要知道如何对字符串进行索引遍历,如何对字符串进行常见的类型编码以及如何实践模式匹配。模式匹配中最直接的方式就是使用正则表达式,这也是咱们应用开发中常常会使用到的技术点。除此以外咱们还须要关注字符串校验、以及如何进行高效模糊搜索等等内容;咱们也能够学习使用 KMP、Sunday 等常见的模式匹配算法来处理搜索问题。浏览器
而后咱们须要学习常见的时间与日期处理方式,了解如什么时候间戳、时区、RFC282二、ISO8601 这些基础的时间与日期相关的概念,了解如何从时间戳或者时间字符串中解析出当前编程语言支持的时间与日期对象。咱们还须要了解时区转换、时间比较以及如何格式化地展现时间等内容,有时候咱们还须要利用日历等对象进行事件的增减以及偏移计算。接下来就是很是重要的集合类型,不管哪一种编程语言都会提供相似于 Array、List、Set、Dictionary、Map 等相关的数据结构实现,而咱们也就须要去了解这些常见集合类型中的增删复替以及索引遍历这些基础操做以及每一个集合的特色;譬如对于序列类型咱们要能熟练使用 map、reduce、filter、sort 这些常见的变换进行序列变换与生成。进阶而言的话咱们能够多了解下这些数据结构的底层算法实现,譬如 Java 8 中对于 HashMap 的链表/红黑树实现,或者 V8 中是如何利用 Hidden Class 进行快速索引的。接下来的话咱们能够对于像 Java 中 SteamAPI 或者各类语言的 Immutable 对象的实现方式有所了解,还有就是常见的 JSON、XML、CSV 这些类型的序列化与反序列化操做库也是实际开发中常常用到的。缓存
接下来咱们就须要对语言提供的经常使用外部功能相关的 API 或者语法有所掌握,主要也是分为存储、网络与系统进程这三个部分。在存储部分咱们须要掌握如何与 MySQL、Redis、Mongodb 等关系型或者非关系型数据库进行数据交互,掌握如何对文件系统进行如文件寻址、文件监控等操做,而且还须要可以使用一些譬如 Java 堆外存储这样的应用内缓存来存放数据。而网络部分咱们应该掌握如何利用 HTTP 客户端进行网络交互、如何使用相对底层的 Socket 套接字创建 TCP 链接、或者使用语言内置的一些远程调用框架与远端服务进行交互。最后咱们须要对如何利用语言进行系统进程操做有所了解,本部分笔者认为最重要的当属并发编程相关知识。在而今服务器性能不断提高、处理的数据量愈来愈多的状况下,咱们不可避免地须要使用并发操做来提升应用吞吐量。并发编程领域咱们应该去学习如何使用线程、线程池或者协程来实现并发,如何利用锁、事务等方式进行并发控制并保持数据一致性,如何使用回调、Promise、Generator、Async/Await 等异步编程模式。除此以外,咱们还须要对切面编程、系统调用以及本地跨语言调用有所了解。
编程语言初学阶段的最后咱们须要了解下工程实践以及一些偏原理与底层实现的进阶内容。首先开发者应当对具体编程语言中如何实现 S.O.L.I.D 编程原则与数十种设计模式有所了解,固然也不能邯郸学步只求形似,而是可以根据业务功能需求灵活地选择适用的范式。而在团队开发中咱们每每还须要统一团队内的样式指南,包括代码风格约定中常见的命名约定、文档与注释约定、项目与模块的目录架构以及语法检查规范等。接下来咱们还须要对语言或者经常使用开发工具的调试方式有所了解,掌握基本的单步调试等技巧,而且可以为代码编写合适的单元测试用例。工程实践方面的最后则是要求咱们对代码性能优化全部了解,尽可能避免反模式。
进阶内容的话则相对更加地抽象或者须要花费更多的精力去学习,其中包括泛型编程、元编程、函数式编程、响应式编程、内存管理、数据结构与算法等几个部分。泛型编程与元编程中的反射、代码生成、依赖注入等仍是属于语言自己提供的语法特性之一,而函数式编程与响应式编程则偏向于实际应用开发中有所偏心的开发范式。即便 Java 这样纯粹的面向对象的语言,当咱们借鉴纯函数、不可变对象、高阶函数、Monad 等函数式编程中常见的名词时,也能为代码优化开辟新的思路。响应式编程是很是不错的异步编程范式,这里咱们还须要注意下并发编程与异步编程之间的差别。而内存管理则有助于咱们理解编程语言运行地底层机制,譬如对于 JVM 或者 V8 的内存结构、内存分配、垃圾回收机制有所了解的话可以反过来有助于咱们编写高性能地应用程序,而且对于线上应用错误的调试也能更加驾轻就熟。
用户界面是前端应用程序的核心组成部分,而咱们涉足前端开发的第一步每每也就是从简单的界面搭建开始。咱们多是在 Android 中编写简单的基于 XML 布局的 Activity,在 iOS 中利用 StoryBoard 快速构建导航界面,或者在 Web 中使用某个框架实现 TODOList。而界面开发最基础的部分就是布局与定位,不管在何端开发中咱们每每都会使用相对布局、绝对布局、弹性布局、网格布局等布局方式;而且面向多尺寸的屏幕咱们每每也须要进行响应式布局的考虑,从横竖屏响应式切换到不一样分辨率下的布局与尺寸的调整,都是为了给予用户较好的使用体验。而了解了布局与定位以后,咱们每每就须要来学习如何使用基本的界面容器,譬如常见的滚动视图、导航视图、页卡视图与伸缩视图。Android 与 iOS 每每也为咱们对这些基本容器进行了较好地封装,而 Web 中则每每须要咱们本身动手去实现相应功能。譬如在滚动视图中,咱们须要去提供常见的滚动事件控制,典型的有如何在不一样环境下保证平滑滚动体验、如何设置优美的滚动条、如何设置滚动监听等等。除此以外,咱们每每还须要针对列表或者长阅读界面封装一些高级事件响应,譬如上拉加载、下拉刷新以及无限滚动时须要的滚动触发规则实现。做为最多见的用户交互方式之一,不管是在移动端仍是桌面端,咱们也都须要实现一些优美的动画;譬如视差滚动就能够给用户带来不同的视觉感觉,而像 Swiper 这样的整页滚动则是很好地产品展现或者讲演页的交互方式。
在基础的界面容器使用中咱们已经接触了一些用户交互的监听与响应的实现,接下来咱们则是须要深刻全面地了解用户交互相关内容。最基础的咱们须要了解经常使用事件与手势操做,了解如何进行事件监听与绑定、如何捕获事件而且进行分发、如何进行缩放、拖拽、摇晃等复杂手势动做地监听与识别、如何响应键盘事件而且进行响应处理。除此以外,笔者将音视频录制与播放,指纹、计步器等传感器的使用,本地通知与远程推送等内容也都概括于了用户交互这个分类下。在 Android 与 iOS 开发中相信对于这些 API 的使用并不会陌生,而随着 HTML5 的流行以及现代浏览器的发展,相信将来 Web 应用也会愈来愈多地添加这些与系统层面进行交互地功能。咱们在本部分还须要了解下动画与变换、绘图及数据可视化等相关内容。常见的动画引擎包含了属性控制与帧动画两种方式,前者更趋向于命令式编程然后者则适用于声明式编程;除了了解这些基础的语法,咱们还须要对经常使用的动画进行收集与汇总,以便在项目开发中可以灵活应用。而随着大数据时代的到来,数据可视化相关应用也成了前端开发常见的任务之一。在这个部分,咱们须要对 SVG、Canvas、WebGL 等相关绘画基础有所了解,可以运用 D3.js 或者其余相似的库进行简单图形绘制。而且咱们要可以利用 ECharts 等优秀的外部绘图库进行散点图、折线图、流程图等常见类型图表进行绘制。最后,地图以及相关技术也是咱们须要去了解的,做为开发者咱们要可以基于百度地图等第三方 API 或者 SDK 开发导航、地理位置信息可视化等相关的功能。
与界面基础相对的就是常见的系统功能以及 API 的使用语法,其主要分为系统与进程、数据存储以及网络交互这三个部分。
在开发多界面应用程序或者利用 Service、ServiceWorker 等方式启动后台线程时,咱们就须要考虑如何进行组件间通讯;譬如在 Android 开发中咱们能够利用 Otto 等库以消息总线的方式在 Activity、Fragment、Service 等组件之间传递消息。而在 Android 或者 iOS 开发中咱们也经常须要考虑并发编程,可能会涉及到如何利用 Thread、GCD 等方式实现多线程并行、如何利用 RxJava 等响应式扩展优化异步编程模型、如何利用锁等同步方式进行并发控制等等内容。有时候咱们也须要去更多地了解系统服务相关的内容,特别是在 Android 或者桌面应用程序开发时,咱们须要考虑如何实现守护进程以协调而且保障各个组件的正常运行。在系统与进程部分的最后,咱们还须要去接触些系统辅助相关的功能实现,譬如如何进行运行环境检测、如何利用 DeepLink 进行 APP 之间跳转、如何进行应用的权限管理等等。接下来咱们讨论下数据存储部分应该掌握哪些内容,最简单的就是相似于 SharedPreference、NSUserDefaults、localStorage 这样的键值类存储;复杂一点的状况咱们可能会利用到 SQLite 或者 IndexedDB 这样的简化关系型或者文档型数据库,有时候 Realm 这样的第三方解决方案也是不错的选择。不少时候咱们还须要了解如何控制缓存或者剪贴板中的内容,以及如何对文件系统进行基本的操做,譬如读写配置文件与资源文件、浏览列举文件系统中的文件而且根据不一样的文件类型选用不一样的处理方式。
而网络交互部分更多地关注如何与服务端或者第三方系统进行交互,实际上对于如何在需求动态变化的状况下较好地协调服务端与客户端对于接口的定义是不少项目开发的痛点。不过从基础使用的角度,咱们首先须要了解如何利用网络客户端进行基于 HTTP 或 HTTPS 的网络请求。这部分咱们须要了解如何构造、分析、编码 URI,如何管理请求头、设置请求方法与请求参数,如何同步、异步或者并发地执行请求,如何进行响应解析,如何进行复杂的请求管理等等内容。除了这些,咱们还要可以利用基础的 Socket 进行通讯,这样有助于咱们理解通讯网络与 TCP/IP 实现原理;咱们每每还须要关心如何利用 WebSocket 等技术实现推送与长链接功能,如何进行远程与本地方法调用等等。除了这三个偏功能实现的知识点,咱们还能够尝试去了解下系统的底层设计原理。譬如在 Android 开发中咱们能够尝试去了解 Dalvik 虚拟机的工做原理,使用 Xposed 或相似工具进行系统层面的一些操做;对于 Web 开发而言咱们能够去更多地关注浏览器工做原理,了解现代浏览器的运行机制等等内容。
在掌握了如何构建基本的界面而且为应用添加必须的功能以后,咱们就须要去尝试进行应用项目开发。每一个应用能够按照用户交互地逻辑切分为多个独立界面,而每一个界面的开发中咱们每每又须要编写导航、菜单、列表、表单等等可重复使用的界面插件。实际上前端开发中最核心的工做之一就是界面插件的开发,好的开发者可以在项目开发中沉淀出可复用的界面插件库;这类可复用的界面插件每每会独立于具体的业务逻辑,其分类天然也应按照显示或者交互逻辑自己,而不该该受制于不一样的业务场景。笔者习惯地会将界面插件区分为指示器(Indicator)、输入器(Picker)、列表与表单(TableGrid)、对话框(Dialog)、画廊(Galley)、WebView 等几个部分。
指示器与输入器算是两个宽泛的界面插件分类,最多见的指示器当属文本显示类别的插件,譬如标签。标签多用于表单中的输入域描述、用户引导等场景,而除了文字标签以外咱们也会使用图标或者所谓的 Tags。除此以外咱们还会关注于 MarkDown 等富文本的展现、如何针对不一样屏幕对页面进行排版与字体设置、如何针对不一样地区的用户进行国际化切换、如何为文本添加合适的动画等等方面。在应用开发中咱们也会添加专门的介绍或引导页,一方面引导用户使用,另外一方面也能够进行后台资源请求与处理;譬如咱们每每会在应用启动时设置闪屏页(Splash),记得最先在 Uber 见到以短视频为背景的闪屏页颇有耳目一新的感受。除此以外,咱们常见的指示器还包括了进度指示与时间指示这两种。在进行数据请求或者数据处理等须要用户等待的场景中,咱们每每会给用户以进度条方式地友好反馈,这种进度条就是典型地进度指示。经常使用的进度条设计有线性进度条、圆形进度条或者固定在页首或者页尾的进度条,有些设计中咱们也会以背景投射地方式反馈当前进度,这种方式可能更具备视觉冲击力。而除了进度条以外,无限循环的加载效果、分页器或者步骤跟踪显示器也是常见的进度指示的表现形式之一。而所谓的时间指示即譬如界面上放置的拟物时钟或者电子时钟、常见于社交媒体上的时间轴或者日历效果以及倒计数效果等。
而输入器的典型表明则为按钮与文本输入,譬如咱们除了常见的 Primary、Secondary 按钮以外,咱们可能还会用到悬浮按钮、可扩展的按钮或者在喜欢与点赞时用到的具备必定动画效果的按钮。而文本输入系列的插件中,除了常见的文本框或者富文本编辑器,有时咱们也须要去编写具备自动补全或者相似于密码、勾选之类的特殊格式的输入框。选择器也是咱们经常使用到的输入器之一,譬如开关、单选按钮、勾选按钮、分段输入以及经常使用于两个列表互选的左右穿梭器等等。除了这些,搜索、菜单、解锁界面也是归属于输入器这个类别中。
在这两个大类以外算得上最经常使用的插件的当属列表、网格与表单这个系列的控件;基本上每一个应用都会包含列表或者网格布局,对于海量数据的列表渲染也是前端常见的挑战之一。Android 中内置的 RecycleView 与 iOS 中内置的 UITableView 都为咱们提供了不错的懒加载、局部渲染的功能,而 Web 中咱们每每须要本身定制或者寻求第三方库的帮助。对于列表的交互也是常见问题之一,除了容许用户正常的点击,咱们还须要添加左滑右滑时的反馈、可伸缩或者容许排序、拖拽的方式进行交互,有时候还须要为了列表项添加进出时的转场动画,以这种微互动增长整个界面的友好性。最后咱们来聊聊画廊与对话框,画廊最典型的插件就是提供图片或者视频预览的走马灯效果的轮播插件,笔者也是将图片加载、呈现、处理相关的插件划分到了画廊这一系列插件中。而在端开发中咱们经常须要对相册或者缓存中的图片进行浏览,或者将图片以瀑布流的方式呈现给用户,这种性质的插件也应归属到画廊这一类中。对话框的分类则稍显的有些生硬,譬如 ActionSheet、HUD 是系统提供的消息提示性质的插件,这种弹出与显示层天然会划归到对话框这个系列的组件中。而在 Web 中咱们经常须要自定义的模态对话框、覆盖层也属于对话框系列,有时候咱们还须要考虑如何为对话框提供拖拽支持,或者在对话框显示和消失之际添加转场动画。
前面咱们讨论了开发某个前端应用所须要的必备技能,而在须要持续交付的团队项目开发中,咱们还须要考虑不少工程实践相关的方法与技巧。命令式编程到声明式编程的变化,将更多地功能性工做交于框架处理,而开发人员更加地专一于业务逻辑的实现。
代码调试是每一个程序员都掌握的技能,不过如何较好地调试代码以快速定位错误所在却并非那么容易。在开发中咱们经常须要热加载、增量编译等相关技术来避免过长的等待,而单步调试则可以帮助咱们梳理代码逻辑、按部就班地发现问题所在。可能 iOS、Android 的开发人员更习惯使用单步调试,而在 Web 或者 Node.js 开发中咱们也应适当地多使用 Chrome 等工具进行代码的单步调试;有时候单步调试也是不错的浏览分析第三方源代码库的方式。另外一方面,日志不管在开发环境仍是生产环境中都可以帮咱们记录应用运行状态等信息。接下来咱们还要了解应用开发周期中不一样阶段使用的单元测试、集成测试以及端到端测试的具体的实现方式,在团队协同开发中统一代码风格与约定,可以利用多种方式对应用进行性能优化,以及在发布到生产环境以后可以混淆加密、进行应用更新以及应用状态跟踪。
所谓架构二字,核心便是对于对于富客户端的代码组织/职责划分,从具体的代码分割的角度,便是功能的模块化、界面的组件化、应用状态管理这三个方面。纵览这十年内的架构模式变迁,大概能够分为 MV 与 Unidirectional 两大类,而 Clean Architecture 则是以严格的层次划分独辟蹊径。从笔者的认知来看,从 MVC 到 MVP 的变迁完成了对于 View 与 Model 的解耦合,改进了职责分配与可测试性。而从 MVP 到 MVVM,添加了 View 与 ViewModel 之间的数据绑定,使得 View 彻底的无状态化。最后,整个从 MV 到 Unidirectional 的变迁便是采用了消息队列式的数据流驱动的架构,而且以 Redux 为表明的方案将本来 MV* 中碎片化的状态管理变为了统一的状态管理,保证了状态的有序性与可回溯性。 实际上从 MVC、MVP 到 MVVM,一直围绕的核心问题就是如何分割 ViewLogic 与 View,即如何将负责界面展现的代码与负责业务逻辑的代码进行分割。所谓分久必合,合久必分,从笔者自我审视的角度,发现颇有趣的一点。Android 与iOS中都是从早期的用代码进行组件添加与布局到专门的 XML/Nib/StoryBoard 文件进行布局,Android 中的 Annotation/DataBinding、iOS 中的 IBOutlet 更加地保证了 View 与 ViewLogic 的分割(这一点也是从元素操做到以数据流驱动的变迁,咱们不须要再去编写大量的 findViewById。而Web的趋势正好有点相反,不管是 WebComponent 仍是 ReactiveComponent 都是将 ViewLogic 与 View 置于一块儿,特别是 JSX 的语法将 JavaScript 与 HTML 混搭,很有几分当年 PHP/JSP 与 HTML 混搭的风味。
从代码组织的角度来看,项目的构建工具与依赖管理工具会深入地影响到代码组织,这一点在功能的模块化中尤为显著。譬如笔者对于 Android/Java 构建工具的使用变迁经历了从 Eclipse 到 Maven 再到 Gradle,笔者会将不一样功能逻辑的代码封装到不一样的相对独立的子项目中,这样就保证了子项目与主项目之间的必定隔离,方便了测试与代码维护。一样的,在 Web 开发中从 AMD/CMD 规范到标准的 ES6 模块与 Webpack 编译打包,也使得代码可以按照功能尽量地解耦分割与避免冗余编码。而另外一方面,依赖管理工具也极大地方便咱们使用第三方的代码与发布自定义的依赖项,譬如 Web 中的 NPM 与 Bower,iOS 中的 CocoaPods 都是十分优秀的依赖发布与管理工具,使咱们不须要去关心第三方依赖的具体实现细节即可以透明地引入使用。所以选择合适的项目构建工具与依赖管理工具也是好的GUI架构模式的重要因素之一。不过从应用程序架构的角度看,不管咱们使用怎样的构建工具,均可以实现或者遵循某种架构模式,笔者认为两者之间也并无必然的因果关系。而组件便是应用中用户交互界面的部分组成,组件能够经过组合封装成更高级的组件。组件能够被放入层次化的结构中,便可以是其余组件的父组件也能够是其余组件的子组件。根据上述的组件定义,笔者认为像 Activity 或者UIViewController 都不能算是组件,而像 ListView 或者 UITableView 能够看作典型的组件。 咱们强调的是界面组件的Composable&Reusable,便可组合性与可重用性。当咱们一开始接触到 Android 或者 iOS 时,由于自己 SDK 的完善度与规范度较高,咱们可以不少使用封装程度较高的组件;凡事都有双面性,这种较高程度的封装与规范统一的 API 方便了咱们的开发,可是也限制了咱们自定义的能力。一样的,由于 SDK 的限制,真正意义上可复用/组合的组件也是很少,譬如你不能将两个 ListView 再组合成一个新的ListView。在 React 中有所谓的 controller-view 的概念,即意味着某个 React 组件同时担负起 MVC 中 Controller 与 View 的责任,也就是 JSX 这种将负责 ViewLogic 的 JavaScript 代码与负责模板的 HTML 混编的方式。 界面的组件化还包括一个重要的点就是路由,譬如 Android 中的 AndRouter、iOS中的 JLRoutes 都是集中式路由的解决方案,不过集中式路由在 Android 或者 iOS 中并无大规模推广。iOS 中的 StoryBoard 却是相似于一种集中式路由的方案,不过更偏向于以 UI 设计为核心。笔者认为这一点多是由于 Android 或者 iOS 自己全部的代码都是存放于客户端自己,而 Web 中较传统的多页应用方式还须要用户跳转页面从新加载,然后在单页流行以后即不存在页面级别的跳转,所以在 Web 单页应用中集中式路由较为流行而 Android、iOS 中反而不流行。所谓可变的与不可预测的状态时软件开发中的万恶之源,咱们尽量地但愿组件的无状态性,那么整个应用中的状态管理应该尽可能地放置在所谓 High-Order Component 或者 Smart Component 中。在 React 以及 Flux 的概念流行以后,Stateless Component 的概念深刻人心,不过其实对于 MVVM 中的 View,也是无状态的 View。经过双向数据绑定将界面上的某个元素与 ViewModel 中的变量相关联,笔者认为很相似于 HOC 模式中的 Container 与 Component 之间的关联。随着应用的界面与功能的扩展,状态管理会变得愈发混乱。