通常程序员都是为各种类型的软件项目进行开发工作。当下在基于云的软件项目中,更多的程序员是致力于 Web 应用的开发。Web 应用的架构一般是由服务端(API 服务)和客户端(浏览器)两个相互交互的部分组成。而我们都知道,客户端主要是用来给用户呈现内容。
早期的 Web 应用客户端都是很轻量的,也就是说,在以前的 Web 应用客户端中处理的业务逻辑比较少。而现在,人们一直致力于构建诸如单页面应用(SPA)的富客户端应用,在这样的富客户端应用中,客户端所包含的业务逻辑在数量和复杂度上都丝毫不亚于服务端。
因此,在现代的 Web 应用开发行业中,就需要聘用更多的前端开发人员来完成客户端的开发工作。现代的前端开发者大部分都是在诸如 React, Angular, Vue, Svelte 等框架上使用 JavaScript 或 TypeScript 进行开发工作。当然也有些程序员会使用架构类似于微前端模式的内部框架进行开发工作。
在前端框架中运用MVVM模式
当下我们正处于通过使用用户电脑的计算能力完成 Web 应用业务逻辑执行和交互内容渲染的时代。在早期 Web 应用中,开发人员将所有的业务逻辑都放在服务端执行,客户端则只负责内容渲染。但是现在更多的 Web 应用通过将 90%左右的业务逻辑放在客户端执行来满足离线应用等需求。
虽然现代的前端框架给开发人员提供了各式各样的开发模式。但所有主流的框架都对使用 MVVM 模式进行编码提供了支持。例如:Angular 将 View 和 ViewModel 分离在 2 个独立文件中(一个 HTML 文件和一个 TS 文件),React 则将 View 和 ViewModel 以组件的形式嵌入在一个 JSX 文件中。
掌握常规 MVVM 模式的知识有助于你快速上手任何前端框架、编写出简洁的 UI 控制程序和可测试的代码。一些开发人员可能会认为 React 既不是 MVVM 也不算 MVC,它只是一个用来操作 View 的库。然而,它却让开发人员以 MVVM 的模式编写代码。因此掌握 MVVM 开发模式,有助于开发人员判断哪些代码应该写在 View 中,哪些代码应该写在 Controller 中。
遵循一般可用性原则
一些在意用户可用性的公司,会聘请 UI/UX 工程师参与到前端开发工作中,甚至有些公司还会成立 UX 团队,专门用于提高公司产品的可用性。通常,UI/UX 工程师的主要工作是原型设计、可用性测试、CSS 和 HTML 编写。然而,大多数公司的前端开发人员也会在工作中使用 CSS 和 HTML。
因此,对于前端工程师而言,不管团队中是否有 UI/UX 工程师,掌握一些一般可行性原则,对其工作都是很有帮助的。例如:你不再需要问 UI/UX 团队,一个确定按钮应该放在左边还是右边。一般可行性原则可以使我们的 Web 应用更加产品化,更加用户友好,更加凸显为用户考虑。
想象一下,每当你开始一个前端开发任务的时候,就需要考虑设计一致性、组件分类、元素排序、颜色、文本尺寸、文本样式、动画、响应设计等因素。然而,大多数应用的原型都没办法全部涵盖。因此,非常有必要花时间学习下一般可用性原则。
编写简洁的异步代码
使用 JavaScript 机可以写出同步代码也可以写出异步代码。众所周知,JS 是单线程的。因此下面这段代码就会让浏览器卡顿几秒。
for(let i = 0; i < 10000000000; i++);
所以我们需要高效利用 JavaScript 的线程机制。出于这个原因,大部分浏览器 API 的设计要么是基于事件机制要么是基于 promise 的异步机制。例如,当你使用 JS 创建一个 WebSocket 链接的时候,JavaScript 不会等待链接真正建立完成,就像下面代码展示的那样:
let ws = new WebSocket('ws://localhost:80'); // 创建ws链接
//ws.send('Hello') will fail // 如果这里执行消息发生,会失败掉,因为ws链接此时还未完成
ws.addEventListener('open', () => {
ws.send('Hello') // works
});
因此我们需要订阅不同浏览器在不同时间执行的事件,这导致我们的 JS 代码变得非常复杂,所以要编写简洁的异步代码还是比较困难的。在处理浏览器事件的时候,部分初级工程师倾向于使用 setTimeout 函数的延迟执行来处理,而不使用合理的事件处理函数。这样就会导致在诸如浏览器、弱网、低端设备等不同客户端上,相同的代码会出现各种各样非预期的行为。
所以,尽可能将事件的处理函数放在一个独立函数体内,避免使用随机延迟函数处理事件回调,在应用上下文退出的时及时清除事件处理函数,不要使用老的回调模式,使用 async/await 模式(如果非要使用,请使用 promise 转换下),避免在行内事件处理中添加业务逻辑。
除此之外,经常练习编写简洁的代码是编写简洁的同步代码的秘诀,下面的文章阐述了每个程序员都可以写出简洁的代码。
软件项目的 5 个简洁代码实践:https://betterprogramming.pub/5-clean-code-practices-for-every-software-project-479443b31c3c
熟悉浏览器 API 是 Web 应用开发的必要条件
老版本的浏览器提供了基本的 DOM 操作 API。后来,由于 JavaScript 的流行,W3C 引入了许多现代 Web API。因此现在我们可以通过使用客户端存储、原生 HTTP 客户端、语音合成、消息通知等 API 来构建更加用户友好的 Web 应用。与此同时,现代浏览器在 DOM 操作和渲染上的支持上也比以前更加的智能和全面。
例如,以前我们并没有很好的方法来处理 DOM 元素尺寸变化的事件,而现在我们只需要使用 ResizeObserver API 就能完成。在处理 RESTful 数据请求上,现在我们可以使用更轻量的 Fetch API 完成,而不再需要使用老的基于 XHR 的第三方库(没错,Axios 也是基于 XHR 的)。
因此,在说“这个在用户浏览器中是无法实现的”这句话之前,我们最好先查看下最新的浏览器 API。现在我们可以利用 WebAssembly API 在客户端浏览器中运行一些高 CPU 消耗的任务。同时我们还可以利用 web workers 编写多线程的 JavaScript 操作。现在几乎没有人使用 IE11 访问现代的 web 应用了,所以在使用正式阶段(非试验阶段)的 web api 时,不必考虑再三。
理解前端的局限性
不知道你是否关注过慢而臃肿的 Web 应用程序?由于诸如冗余 UI 元素、静态资源未做 CDN 加速、沉重的第三方库或框架等原因,Web 应用通常会变的慢而臃肿。与此同时,如果你将大量的业务逻辑放在客户端执行,也会导致 Web 应用渲染的比较慢。在不阻塞 JS 线程的情况下,将一些数据的排序和筛选放在客户端是没问题的,否则就需要将这些数据处理的操作放在服务端或者数据库。
虽然 JavaScript 通过非阻塞操作提供了一种类似并行的机制,但一个浏览器实例在同一时间点是不能同时完成 2 个 JavaScript 操作的,因此大量的数据操作会必然会让你的 Web 应用变的很慢。除此之外,过多的事件处理也会影响使 Web 应用变慢。所以需要确保事件处理的高效性,而且在应用上下文退出的时候,也要及时清理事件处理函数。
相对于基于云计算的后端服务,客户端的资源是非常有限的。现在,人们依然在使用低端或中端的终端设备访问互联网。因此,一旦你在客户端实现了比较重的功能时,就需要关注 Web 应用程序的内存占用描述文件。
例如:下面的内存占用描述文件给出了 YouTube 在视频播放期间,其内存使用的信息。只需将下面的内存使用统计数据与您正在构建的 Web 应用程序的内存使用情况进行比较即可。