18

前端之变(六):引领式变革,从命令式UI到声明式UI

 3 years ago
source link: https://my.oschina.net/lingenliu/blog/5114822
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前端之变(六):引领式变革,从命令式UI到声明式UI - 御剑_lingen的个人空间 - OSCHINA - 中文开源技术交流社区

当我在2020年使用前端的技术栈去编写一个跨平台桌面App时,发现前端在UI方面其模式与我在移动端接触到的有很大的差异,那时候我意识到原来在前端,其UI使用的是另一种模式,后面我才知道它的名字:声明式UI

事实上,前端本身也经历了变革,至少在JQuery时代,它与移动端一致,其UI模式仍然属于传统的命令式UI,但到了React及Vue的时代,它变成了声明式UI。从我有限的知识来看,至少在大前端的其它两个方向:移动端与桌面开发,并未优先引领式的出现这种变革。

因此,我把前端的这种变革,称之为:引领式变革

它改变的不仅仅是自己。而且正在改变移动端,无论是Android官方自己主推的Jetpack,还是iOS官方新的UI框架SwiftUI,与之前也完全不同,都从命令式UI变为声明式UI。很难说这种变革,没有受到前端的影响或借鉴。

这说明前端技术变革不仅改变了自身,甚至在一些方面走在了更前面。

本周,继续就前端之变阐述自己的思考与分析。这是第六篇。前面几篇分别是:

命令式与声明式

首先,要明确一个前提,UI这个事情,只在大前端才有。所以,无论是命令式UI还是声明式UI,在后端编码是不存在这个概念的。

当然,若干年前,后端兼顾前端页面的开发,但那个时代已经过去了。现在主流的模式应该是前后端分离,由后端人员同时来开发前端,比如用JSP或FreeMarker模板技术的做法,在现在应该不多见了,不能算主流了。

UI这个事情并非只在Web前端才有,事实上,在技术的几个方向,除了后端以外,包括前端,移动端及桌面端都存在UI。

因此,无论是命令式UI,还是声明式UI,其概念是同时适应于前端,移动端以及桌面端的。

在这个前提之下,我们就可以来仔细分析下,在前端发生变革以前,事实上无论是在前端,移动端还是桌面端,其UI的编码模式都属于命令式UI

什么是命令式UI

UI的更新是由程序员使用代码主动刷新,UI与数据并无必然的映射关系,这种我们称之为命令式UI

什么是声明式UI

UI的更新并非由程序员使用代码来主动刷新,而是由后面隐藏机制来负责维护UI的刷新,UI与数据有映射关系,这种我们就称之为声明式UI

上面这种定义是我的定义,根据上述定义,区分是命令式UI还是声明式UI的两个核心点是:

  1. 程序员是否要显式的去调用代码刷新UI
  2. UI与数据是否存在映射关系

传统UI模式:命令式UI

我们回到过往的时光,在那个还是JQuery主导前端开发的时代,我们设想一个最简单的需求:记住上一次的登录用户名

我在这里用前端与移动端的代码来示例,展现命令式UI的做法:

//基于JQuery的实现
const lastLoginUsername = localstorage.getItem("lastLoginUsername")
$("#username").val(lastLoginUsername);//主动刷新UI
//Android + Java
String lastLoginUsername = preferences.getString("lastLoginUsername", "");
usernameInput.setText(lastLoginUsername);//主动刷新UI

上述的这些实现,就是典型的命令式UI,它都具备几个特点:

  • 在程序中,你可以显式的引用或拿到UI组件
  • UI组件的内容是怎么样,什么时候改变内容,都是由程序员在合适的时候进行处理。UI本身与数据并无直接的映射关联,都是由程序员将数据显式的注入到UI中。

无论是传统的前端开发,还是我前些年开发原生iOS与Android,都统一属于这种模式。它们都毫不例外的属于命令式UI。

这种命令式UI的模式,是存在一些问题的,表现在:

UI维护工作较重

从上面我的描述可以看出,整体UI行为,怎么样,什么时候怎么改变,要全部由程序员使用代码来处理。可想而知,这个过程显然是非常繁重的。事实上,可以说,无论是过往的前端,还是现在的移动端,可能有相当一部分工作都是在处理UI的各种刷新上面。

易于出错

很显然,需要刷新UI的时机很多,比如下拉刷新,通知数据变更,网络不好数据加载错误,其它模块变更引发的联动UI变更等等,很多情况下需要你处理UI的刷新工作。

需要处理的事情一旦多起来,出错的概率就再所难免了。

性能不佳

通过一个UI包含很多内容与组件,但需要刷新时,你是怎么处理刷新的?

是不管三七二十一,将所有UI内容全部设置一下,还是先对比下,有改变的再刷新,没改变的不再刷新?

可能有相当一部分比例,是属于全部设置一下的做法。这种的性能肯定不会太好,产生了许多不必要刷新。

当然,如果你比对然后只尽量做必要性的刷新,那这个事也有相当的复杂度的,而且可能易于出错。

UI与数据易出现不一致

想像一下吧,你的代码中有一份数据,这份数据决定了UI的展现,但事实上程序员是分开处理这两个部分的,由一些代码来调用刷新数据,再由一些方法现刷新UI,无论你做的多么周到,出现数据变更 ,UI却忘记刷新的可能性仍然是非常高的。

因此,UI与数据出现不一致的可能性极高。

所幸,声明式UI出现了,它极大的改善了这些问题。

变革之道:声明式UI

声明式UI与命令式UI的最核心的区别在于:

  1. UI是数据的映射与描述,甚至一些框架中,程序员是无法持有UI组件的。更谈不上去调用这个组件的方法刷新UI了。
  2. 程序员关心的只是数据,只需要在合适的时机刷新数据就行了。UI则根据映射,由技术背后的机制帮你去刷新处理。

很显然,这是对命令式UI做了根本性的改变。

我在这举一个简单的例子,仍然以记住上一次登录用户这个需求为例。

//代码做了删减,只保留了有关的部分
export const LoginView = observer(() => {

  const [username, setUsername] = useState(localStorage.getItem('login_username'));

  return (
    <input className="input_username" value="{username}" onChange="{e" => setUsername(e.target.value)} />
  );
});

这是一个React代码,你可以看到,input_username这个输入框的值是{username}这个变量,而要修改这个输入框的值的方式,也不是调用UI的方法去设置值,而是通过改变username这个变量来实现。

所以,修改这个UI的内容的方法是

onChange={e => setUsername(e.target.value)}

一旦你改变了username的值,input_username的内容自动的刷新改变了,并不需要程序员去介入UI的刷新工作。

这就是声明式UI

声明式UI如果要论述,可以说的很多,我这篇文章的目的不在于此。就不详细去解释它了。

当然,很明显,与命令式UI相比,上述的几个缺点都有所改善:

程序员没有复杂的UI操作

在声明式UI中,程序员要做的就是定义数据与UI的映射关系而已,一旦定义好后,后面只需要关心数据的维护,不需要再关心UI的刷新了,这极大的减轻了程序员的在UI上的工作。

事实上,以我个人编写移动端与前端的经历来看,前端的UI编写的确更快,更有效率

难以出错

显而易见的是吧,UI刷新是由框架或技术背后实现的,你只需要刷新数据就可以了,框架或技术的可靠性保证了不太可能出现数据刷新了,UI却没刷新或刷新出错的情况。

极高的性能

由于对数据的映射与刷新是框架在背后处理的,通过大部分框架都不会数据一变就全量刷新,这就太low了。

比如,React就有一个diff算法,这个算法保证了只进行必要的刷新,这是非常高效的做法。

UI与数据的一致性

你只需要关心数据,变更数据。并不需要担心数据与UI出现不一致的情况。

在框架质量有所保证的前提下,这种可能几乎为小的可以忽略不计。(框架也可能有BUG,不能期望它为0)

趋势,大前端UI的未来

当然,『后』前端阶段,无论是React或Vue,都已经是这种声明式UI的做法了,它已经是前端的事实与主流了。

而在移动端,Android现在本身主推的是Jetpack,而iOS主推的是SwiftUI,这些也都是声明式UI了。但在移动端,它们仍然只是趋势,移动端现在绝大部分主流可能仍然是过往的命令式UI。

但可想而知,就算移动端,未来也必然会转向声明式UI。

至于移动端非原生的技术,类似Flutter,React Native等就不用说了,这些已经是声明式UI的实现了。

至于桌面端,由于我只有基于Electron开发桌面软件的经验,这是个前端技术,当然也是声明式UI,至于原生Window或Linux桌面开发,我并未有相关经验,但我相信借鉴声明式UI也绝对是正确的趋势。

所以,做为一个大前端的程序员,无论你是前端或是移动端,还是桌面端,你都要做好迎接声明式UI的未来的准备。

前端发生了巨大的变革,如我所言,这种变化是革命性的,颠覆性的。

但从我在前端的经验来看,无论是前端语言的生态,还是质量,与后端仍存在一些差距,这就非常值得我的思考,如果理念与技术并没有问题,那问题究竟在哪?

下一篇,前端之变(七):前端之困,继续就前端阐述我的思考与分析。


关注【微言码道】公众号或访问【微言码道】官网 https://taoofcode.cc : 用我们微小的力量传播编码之道

访问【myddd-全栈式领域驱动】官网: https://myddd.org


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK