前端技术演进(七):前端跨栈技术

这个来自以前作的培训,删减了一些业务相关的,参考了不少资料( 参考资料列表),谢谢前辈们,么么哒 😘

随着互联网架构的不断演进,前端技术框架从后台输出页面到后台MVC,再到前端MVC、MVP、MVVM,以及到Virtual DOM和MNV*的实现,已经发生了巨大的变化。总体上来看,前端也正在朝着模块化、组件化和高性能Web开发模式化的方向快速发展。除了传统桌面浏览器端Web上的应用,前端技术栈在服务端或移动端上的尝试和发展也历来没有中止过,并且造成了一系列成熟的解决方案。前端的技术栈能解决的不仅是页面上的问题,前端工程师的追求也毫不只是页面上的技术。html

跨后端技术

这几年全栈工程师已成为一个很热门的关键词,从最先的MEAN技术栈到后端直出,再到如今的先后端同构,前端经过与Node结合的开发模式愈来愈被开发者认同并在愈来愈多的项目中获得实践。前端开发者都热衷于在Node上开发有如下几个缘由:前端

  • Node是一个基于事件驱动和无阻塞的服务器,很是适合处理并发请求,所以构建在Node上的应用服务相比其余技术实现的服务性能表现要好。
  • Node端运行的是JavaScript,对于前端开发者来讲学习成本较低,要关注的问题相对来讲比前端更纯粹些。
  • 做为一名前端工程师确实须要掌握一门后台语言来辅助本身的技术学习。
  • Node端处理数据渲染的方式可以解决前端没法解决的问题,这在大型Web应用场景下的优点就体现出来了,这也是目前Node后端直出或同构的实现方式被开发者普遍使用的一个重要缘由。

Node后端开发

Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时。react

有个叫Ryan Dahl的歪果仁,他的工做是用C/C写高性能Web服务。对于高性能,异步IO、事件驱动是基本原则,可是用C/C写就太痛苦了。因而这位仁兄开始设想用高级语言开发Web服务。他评估了不少种高级语言,发现不少语言虽然同时提供了同步IO和异步IO,可是开发人员一旦用了同步IO,他们就再也懒得写异步IO了,因此,最终,Ryan瞄向了JavaScript。在2009年,Ryan正式推出了基于JavaScript语言和V8引擎的开源Web服务器项目,命名为Node.js。web

Node第一次把JavaScript带入到后端服务器开发,加上世界上已经有无数的JavaScript开发人员,因此Node一会儿就火了起来。Node最大的优点是借助JavaScript天生的事件驱动机制加V8高性能引擎,使编写高性能Web服务垂手可得。sql

阻塞和非阻塞

阻塞 是说 Node.js 中其它的 JavaScript 命令必须等到一个非 JavaScript 操做完成以后才能够执行。这是由于当 阻塞 发生时,事件机制没法继续运行JavaScript。数据库

在 Node.js 中,JavaScript因为 CPU 密集操做而表现不佳。而不是等待非 JavaScript操做 (例如I/O)。这被称为 阻塞编程

阻塞 方法执行起来是 同步地 ,可是 非阻塞 方法执行起来是 异步地 。 使用文件系统模块读取一个文件,同步方法看上去以下:后端

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // 这里会阻塞复制代码

与之功能等同的 异步 版本:react-native

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});复制代码

在第二个例子中, fs.readFile() 由于是 非阻塞 的,因此 JavaScript 会继续执行,不会发生阻塞, 这对于高效吞吐来讲是绝佳的设计。浏览器

在 Node.js 中 JavaScript 的执行是单线程的,因此并行与事件轮询能力(即在完成其它任务以后处理 JavaScript 回调函数的能力)有关。任何一个企图以并行的方式运行的代码必须让事件轮询机制以非 JavaScript 操做来运行,像 I/O 操做。

好比 每一个对服务器的请求消耗 50 毫秒完成,其中的 45 毫秒又是能够经过异步操做而完成的数据库操做。选择 非阻塞 操做能够释放那 45 毫秒用以处理其它的请求操做。这是在选择 阻塞非阻塞 方法上的重大区别。

Node.js 中的事件轮询机制和其它语言相比而言有区别,其它语言通常须要建立线程来处理并行任务。

MEAN

Node出现的早期还不像如今同样拥有很复杂的概念,相关技术和语言的标准还不成熟,Node开发通常用的比较多的方案就是使用Express做为Web框架进行小型的Web站点建设,与之结合的主流技术则以M(Mysql)、E(Express)、 A(Angular)、 N(Node)最为典型,甚至到了今天MEAN技术组合的方式仍在沿用。

image.png | center | 712x530

前端通常使用Angular来管理实现页面应用,服务端Web框架以Express为主,同时使用免费开源的MongoDB数据库,这样就能够很快地构建一个Web应用了。

今天可能不必定再去选择使用它,由于能够代替实现的成熟方案已经不少了,各种其余先后端框架均可以用来灵活组合做为MEAN的替代选型方案,好比 Vue、React能够替代 Angular,Koa 能够替代 Express,数据库的选择也有不少。

Node后端数据渲染

对于前端开发者来讲,在大型Web应用开发中,不少时候并不须要彻底从新设计整个应用后台的架构,更多的状况下须要结合Node的能力帮助咱们解决先后端分离开发模式下没法解决的问题。咱们先来看下一般先后端分离的开发模式下有哪些问题,利用Node 端的服务又是如何帮助咱们解决这些问题的:

SPA场景下SEO的问题

一般状况下,SPA应用或先后端分离的开发模式下页面加载的基本流程是:

  1. 浏览器端先加载一个空页面和JavaScript 脚本。
  2. 而后异步请求接口获取数据。
  3. 渲染页面数据内容后展现给用户。

那么问题来了,搜索引擎抓取页面解析该页面HTML中关键字、描述或其余内容时,JavaScript还没有调用执行,搜索引擎获取到的仅仅是一个空页面,因此没法获取页面上<body>中的具体内容,这就比较影响搜索引擎收录页面的内容排行了。尽管咱们会在空页面的<meta>里面添加keyword和description的内容,但这确定是不够的,由于页面关键性的正文内容描述并无被搜索引擎获取到。

若是使用Node后端数据渲染(有人称之为直出或服务端渲染 SSR),在页面请求时将内容渲染到页面上输出,那么搜索引擎获取到的HTML就已经包含页面完整的内容,页面也就更容易被检索到了。

前端页面渲染展现缓慢的问题

除了SEO问题,在先后端分离的开发模式下页面在JavaScript执行渲染以前是空白的(或提示用户加载中)。用户在看到数据时已经花费的网络等待时间包括:

DOM下载时间 + DOM解析时间 + JavaScript 文件请求时间 + JavaScript部分执行时间 + 接口请求时间 + DOM渲染时间。

这时用户看到页面数据时已是三次串行网络资源请求以后的事情了。若是使用后端直出来进行数据渲染,首先SEO的问题不复存在,用户浏览器加载完DOM的内容解析后便可当即展现,网络加载的问题也获得解决。其余的逻辑操做(如事件绑定和滚动加载的内容)则可按需、按异步加载,从而大幅度减小展现页面内容花费的时间。

通常后台页面数据直出的通用架构设计以下:

image.png | center | 600x446

直出层接受前端的路由请求,并在Node端的Controller层异步请求服务接入层接口,得到Model数据并进行组装拼接,而后提取相对应的Node端View模板渲染出HTML输出给用户浏览器,而不用经过前端JavaScript请求动态数据后渲染。

不只如此,直出层根据不一样的浏览器userAgent,也能够提取不一样的模板渲染页面返回给不一样的用户浏览器,因此这种实现方式不只很是适合大型应用服务的实现场景,并且能够方便地实现网站的响应式内容直出。

先后端同构

在先后端分离的开发模式上加入直出层,解决了SEO和数据加载显示缓慢的问题。但是有两个新的问题:

  • 前端的开发实现向直出层偏移,不得不在原来的开发模式上作出修改来 适应直出层内容的开发,例如修改后端模板来适应现有的开发模式,结果咱们不得不维护两套不一样的先后台模板或技术实现——前端渲染实现逻辑和后端直出实现逻辑,尽管可能都是用JavaScript写的。
  • 若是是在移动端Hybrid应用上,离线包机制实现可能就会出现问题。由于每次都是从后端直出HTML结构给前端,这样就难作到将HTML文件进行离线缓存,而只能进行其余静态文件的缓存。在Hybrid App的应用场景下,其实咱们更但愿作到的是移动端首次打开页面时使用后端直出内容来解决加载慢和SEO问题,而在有离线缓存的状况下则使用客户端本地缓存的静态文件拉取数据返回渲染的方式来实现,或者将来在高版本的浏览器支持HTTP2的条件下使用前端渲染,低端浏览器不支持HTTP2的状况下则使用直出的方式实现。

因此须要一套完善的开发方式,和原有开发方式保持一致,且可以同时用于先后端分离的开发模式和后端数据渲染模板开发方式中。这种开发模式就是咱们所说的先后端同构。

实现同构的核心

先后端同构的宗旨是,只开发一套项目代码,既能够用来实现前端的JavaScript 加载渲染,也能够用于后台的直出渲染。

为何能够这样作呢?和前端渲染数据内容的方式相同,页面直出层内容也是经过数据加上模板编译的方式生成的,前端渲染和后台直出的模式生成DOM结构的区别只在于 数据和模板的渲染发生在何时。若是使用一套能在前端和后端都编译数据的模板系统,就能够作到使用同一套开发代码在先后端分别进行数据渲染解析。所以先后端同构的核心问题是实现先后台数据渲染的统一性。

同构的优点

除了解决先后端开发方式的问题,先后端同构的网站具备一些明显的优点:

  • 能够根据用户的需求方便地选择使用前端渲染数据仍是后台直出页面数据;
  • 开发者只需维护一套前端代码,并且能够沿用前端原有的项目组件化管理、打包构建方式,根据不一样的构建指令生成相似的先后端数据模板或组件在先后端执行解析,因此这对于DOM结构层上的开发方式应该是一致的。

先后端同构的实现原理

基于数据模板的先后端同构方案

早在前端MVC开发的时代,前端模板的使用就很是普遍,例如Mustache、Handlebar 等,基本原理是将模板描述语法与数据进行拼接生成HTML代码字符串插入到页面特定的元素中来完成数据的渲染。同理,后端直出层也能够经过该方法来实现数据的渲染产生HTML字符串输出到页面上。

若是先后端使用同一个模板解析引擎,那么咱们只须要编写同一段模板描述语法结构就能够在前端和后端分开进行渲染了。好比一样的模板:

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>复制代码

前端,后端拿到数据后解析保持一致:

{
  "title": "Hello",
  "body": "World"
}复制代码
<div class="entry">
  <h1>Hello</h1>
  <div class="body">
    World
  </div>
</div>复制代码

对于前端开发的同一段模板语法结构,咱们既能够选择在浏览器端渲染生成HTML字符串输出,也能够选择在后端渲染生成HTML字符串输出。若是选择在前端渲染,则能够将模板进行打包编译,在数据请求成功后进行DOM渲染;若是选择后端渲染,就能够将模板数据直接发送到直出层的View视图进行渲染,实现同一个模板语法结构在先后端渲染出相同的内容。这里的前提是要保证先后端使用的模板渲染引擎或者模板解析的语法是一致的。

基于MVVM的先后端同构

MVVM框架页面上的JavaScript逻辑主要是经过Directive(不仅是Directive,还有filter、 表达式等,以Directive为主)来实现的,通常前端页面加载完成后会开始扫描DOM结构中的Directive指令并进行DOM操做渲染或事件绑定,因此数据的显示仍然须要页面执行Directive后才能完成。那么若是将Directive的操做在直出层实现,浏览器直接输出的页面就是渲染后的内容数据了。

<div class="entry">
  <h1 x-html="title"></h1>
  <div class="body" x-html="body"></div>
</div>复制代码

前端编写的同一段MVVM的语法结构,经过前端MVVM框架解析或后端Directive 运行解析最终均可以生成相同的HTML结构,不一样的是前端执行解析后生成的是ViewModel对象并经过浏览器体现,后端渲染则生成HTML标签的文本字符串输出给浏览器。这里一样须要作一件事,即在后台实现一个与前端解析Directive相同的模块,甚至还包括filter、语法表达式等的实现。这样就能够在先后端完成同一段语法结构的解析了。

基于VirtualDOM的先后端同构

以前说过,VirtualDOM做为一种新的编程概念被普遍应用在实际项目开发中,其核心是使用JavaScript 对象来描述DOM结构。那么既然Virtual DOM是一个JavaScript对象,就表示其能够同时存在于先后端,经过不一样的处理方式来实现同构。

在前端开发的组件中声明某段VirtualDOM描述语法,而后经过VirtualDOM框架解析生成VirtualDOM,这里的VirtualDOM既能够用于在浏览器端生成前端的DOM结构,也能够在直出层直接转换成HTML标记的文本字符串输出,后面这种状况就能够在服务端上实现Virtual DOM到HTML文本字符串的转换。这样,经过对Virtual DOM的不一样操做处理,就能够统一先后端渲染机制,实现组件的先后端对同一段描述语法进行渲染。

这里VirtualDOM上的逻辑实现仍然须要在浏览器端进行事件绑定来完成,最好能让同构框架帮助咱们自动完成,根据HTML的结构进行特定的事件绑定处理,保证最后展现给用户的页面是完整且带有交互逻辑的

不管哪种方式,核心都体如今HTML的结构形式变化上,页面内容的描述方式有不少,并且能够经过特定的处理过程实现转化,这样就提供了更多的可能性。

image.png | center | 390x370

Egg.js

image.png | center | 89x28

Node虽然生态比较火热,可是至今尚未一款公认的成熟的企业级框架,主要是由于使用Node来开发大型后端应用的企业还不多。如今主要有两款:Sails 和 Egg.js。

设计原则

一个插件只作一件事:Egg 没有内置不少额外的功能,而是经过插件的方式来实现,Egg 经过框架聚合这些插件,并根据本身的业务场景定制配置,这样应用的开发成本就变得很低。

约定优于配置:按照一套统一的约定进行应用开发,团队内部采用这种方式能够减小开发人员的学习成本,这也是不少框架的思路。

特色

  • 提供基于 Egg 定制上层框架的能力:能够基于 Egg 去封装适合团队的上层框架。
  • 高度可扩展的插件机制:能够促进业务逻辑的复用,生态圈的造成。
  • 内置多进程管理。
  • 基于 Koa 开发,性能优异:支持全部的Koa中间件。
  • 框架稳定,测试覆盖率高。
  • 渐进式开发:能够流畅的实现编码 --> 编码抽象成功能 --> 功能抽象成插件 --> 插件封装到框架 的渐进过程。

eggjs.org/zh-cn

如今咱们部门的Node项目基本上是 Koa,Egg流。其余部门也有 Express 流。

跨终端技术

移动端

移动互联网兴起后,智能移动设备出现,大量应用市场的Native应用也开始涌现。随着第一波移动端互联网开发浪潮渐渐平静,各种Native应用开始进入有序更新迭代的阶段。人们对移动互联网需求急剧增加,Native 应用快速迭代开发的需求也愈来愈多,可是现有Native应用的开发迭代速度依然没法知足市场快速变化的须要。随之而来的是HTML5的出现,它容许开发者在移动设备上快速开发网页端应用,并让移动互联网应用开发很快进入了Native应用、Web应用、Hybrid 应用并存的时代。

image.png | center | 600x305

在发展过程当中,最大限度的利用原生能力成为了一大趋势。出现了 React Native、Weex 等框架,能够直接使用 Javascript 来编写原生应用。好比React Native,产出的并非“网页应用”, 或者说“HTML5应用”,又或者“混合应用”。 最终产品是一个真正的移动应用,从使用感觉上和用Objective-C或Java编写的应用相比几乎是没法区分的。

import React, { Component } from 'react';
import { Text, View } from 'react-native';

class WhyReactNativeIsSoGreat extends Component {
  render() {
    return (
      <View>
        <Text>
          若是你喜欢在Web上使用React,那你也确定会喜欢React Native.
        </Text>
        <Text>
          基本上就是用原生组件好比'View''Text'
          来代替web组件'div''span'。
        </Text>
      </View>
    );
  }
}复制代码

image.png | center | 618x544

也就是说即便不懂原生应用的开发,也能够用 Javascript 来编写原生应用了。

桌面端

如今,也可使用 JavaScript, HTML 和 CSS 构建跨平台的桌面应用。经过 Electron 之类的应用,能够直接把 Web 项目打包成桌面应用,运行在各个操做系统中。

著名的 Atom IDE 就是经过 Electron 构建的,其余的包括 VS Code、Skype、Github Desktop 之类的 App 也都是经过 Electron 构建的。

image.png | center | 718x902

相关文章
相关标签/搜索