高层前端架构。 Yandex讲座

选择正确的体系结构是构建前端服务的关键部分。 开发商Anna Karpelevich告诉界面开发学院的学生什么是架构,它执行什么功能以及解决什么问题。 从讲座中,您可以了解前端最受欢迎的架构方法:Model-View- *和Flux。


晚上好 我叫安雅·卡佩列维奇(Anya Karpelevich)。 今天,我们将讨论顶级前端的体系结构。

我在Yandex.Direct工作。 我们为广告客户提供界面。 他们发布广告,对其进行自定义。 这是一个非常复杂,有趣的系统,它具有许多相互连接的组件,它们相互成长,并具有共同的功能和自己的功能。 “裤子变成优雅的短裤。” 所有这些都必须非常仔细地控制。 而且我们应用程序中的体系结构非常复杂。 这就是我今天进行此讲座的原因之一。 我真的很喜欢这个话题。

什么是建筑? 事实是这个问题可能没有答案。 还是有,但是每个都有自己的。 这是一个非常有争议的话题。 它引起了很多争议,引发了很多争议。 我今天要谈的很多是我的看法。 我的工作组部分支持它,部分不是非常支持。 每个人在编写应用程序体系结构时都会自己决定如何做。

这就是为什么体系结构是程序员工作中最具创造力的地方之一的原因。 因此,我们今天的演讲也将从创意开始。



让我们看左图。 如果有人意识到上面显示的建筑物,我将感到非常高兴。 这是巴黎的圣叙尔皮斯教堂。 请注意炮塔,因为这座炮塔是为了这座教堂而建。 我希望他们有所不同。 它们是完全不同的,并且有一个有趣的原因。 他们之间相差130年。 然后在普法战争期间左塔被拆毁并重建。

她怎么在这里 看这张照片。 这些塔具有相同的体系结构,并且整个环境,这些渐晕,固定装置,拱形结构都不同。 为什么这样 因为这些塔的目的是相同的。 例如,其中没有一个是钟楼。 这些只是塔。 有些东西存储在其中,其他所有东西都不一样。 怎么了 因为这些塔的架构是相同的。 两者都有一个金库,只有一个窗口,是柳叶刀。 窗户的高度大致相同。 想法是,建筑,包括建筑物和应用程序,都是支撑结构。 这不是装饰图案,不是闪烁,不是实现。 这是核心。 通常,这种基础取决于环境,土壤,建筑方面,也取决于建筑师为自己设定的目标,但几乎从不依赖于设计改进。

建筑主题的建筑示例非常明显。 但是正确的图片更有趣。 “建筑是麻木的音乐。” 18世纪的约翰·沃尔夫冈·歌德(Johann Wolfgang Goethe)说:“建筑学家gefrorene Musik”。 歌德很可能对建筑物的建筑一无所知,他是一位诗人。 并且保证他对应用程序架构一无所知。 但是他表达了一个非常有价值和有趣的想法。

音乐存在于动态之中。 这不是静态的。 这是一个过程。 就像那样,应用程序就是一个过程。 当我们和他一起做某事时,他有一个发展的时刻,一个发展的时刻。 他终于有了片刻的完成。 应用程序的体系结构是它在任何给定时间的分片。 在任何时候,我们作为音乐主题的应用程序都应该清晰,清晰,可理解,可预测等。否则,一切都会崩溃。

通过这一创造性的介绍,我们结束了更平凡的工作,更接近于构建应用程序的实践。

什么是架构,为什么需要它?



首先,我们组织了大量的代码,这在Direct中,而不仅仅是Direct中,总是会遇到。 有太多代码,您可能会迷失其中。 我们不想在代码中迷路。

其次,功能重复。 这也是您将永远遇到的一个永恒的问题,今天,这个重复的主题将贯穿整个演讲的红线。 我们可能需要在界面上的多个位置使用相同的功能。 如果在多个地方都需要它,那么它在物理上必须是在多个地方使用的相同代码,而不是副本。 怎么了 我们将进一步讨论。 但是体系结构应该可以帮助我们避免复制粘贴。

第三是支持。 很明显,如果我们有一个应用程序,那么我们就需要以某种方式支持它,并且建议不要将所有团队的资源都浪费在此上。

改变团队的组成。 这也是我们在现实生活中遇到的次数比我们想要的更多的事情。 有人来了,有人离开了,如果一个人花六个月的时间来输入密码,那就不好了。 如果仅将代码知识存储在一个头中,并且在离开的情况下它将在六个月内传输该知识,那就更糟了。 总的来说,这里的体系结构还可以帮助我们使所有这些变得更易于理解,并保持知识共享。

添加和扩展功能。 也很明显。 经理来找我们,说这是迫切需要的。 而且,如果要紧急执行此操作,您必须花费大量时间和精力,那么这是一个糟糕的体系结构解决方案。 我们需要好的。

最后是错误。 我们的体系结构越容易理解,可预测,发现错误就越容易,错误越少。

如何称呼这一切? 所有这些都可以称为-复杂系统的问题。 应用程序是一个复杂的系统;体系结构可帮助我们解决问题。



简而言之,莫名其妙。 这是我右边的面条照片,如果您不遵循体系结构,或者不进行构建,请仔细考虑并设计,就会发生这种情况。 第二张图是如果至少通过某种方式对体系结构进行了思考会发生什么。 这不是Saint-Sulpice,但至少是儿童设计师,他站稳而不会崩溃。 今天,我们还将扮演很多构造函数。



正式关于这一切。 架构是一种通过从接口抽象实现并区分代码块之间的能力来解决复杂系统问题的方法。 进一步,我们将详细分析这个长短语。

作为知识领域的应用程序体系结构有哪些特征? 她在与我们合作的特定领域。 也就是说,它不是抽象的东西,而是非常具体的东西。 这是任务,我们为它选择体系结构,而不是,因此,我们必须尝试一种有趣的体系结构方法。 所以没有 您可以尝试一些较小的事情,但是对于一个严肃的项目,则选择了体系结构,有时是为特定项目组成的。

问题的历史,通常是这种想法产生于应该进行体系结构的时候。 我必须说,1968年,出色的程序员Edsger Dijkstra提出了一个非常特别的想法。 他可能是Dijkstra算法(在图形中搜索最短路径)的作者而广为人知。 但实际上,他的时代有很多突破性的想法。 其中一篇是文章,然后我将为您提供参考材料,您可以阅读,只有两页,一篇短文。 听起来像“ GOTO操作员被认为是有害的”,翻译为“ GOTO操作员-无条件过渡的操作员-邪恶”。 这是第一个让我们正式说我们需要编写建筑而不是面条的想法。

在20世纪70年代,Dijkstra已经与Parnassus合作,并各自独立地提出了这个想法。 关于应用程序体系结构的第一本详细书籍一般由Mary Shaw和David Garlan于1996年撰写。 在那之后,实际上,关于软件体系结构的这些详细书籍并不是因为范围而写的,因为每个知识领域都有自己的体系结构方法,在某个地方,某个地方更流行,通常在某些地方不适用。 而且由于架构是一个创造性的过程,因此您不会找到有关如何编写架构的任何特定书籍。 也许在1996年以后,没有关于此主题的特别详细的信息。

现在对该项目的架构有哪些要求。 首先,也是最重要的一点,实际上,它所需要的就是可扩展性,因为如果您的项目不扩展,那么它就死了。

重用代码。 这是关于非常复制粘贴。 如果您有两个块在两个不同的地方使用,则需要相同的功能,那么您需要重用相同的代码,并且该体系结构应确保可以立即使用和重用任何一段代码。 。

代码模块之间的权限分离。 我们今天将更详细地讨论这一点,以及为什么这样做是必要的。 这个想法是这样的:每个模块,每个块,每段代码都必须执行一个特定的动作,并恰好带有一个功能。 这个函数应该放在该方法的标题(类,无论可能是什么)中。 一个模块-一个功能。

最后是应用程序的质量。 我想做很多事情-可靠性和向后兼容性。 实际上,再次为任务选择了它。 需要向后兼容,以便在任何情况下都不会移动。 需要某种可靠性的地方,上帝禁止,密码,卡或CVV的密码不会泄漏到任何地方。 如果是卫星或其他东西,您需要在某个地方实现无故障。 通常,选择任意几个。 您想要支持的越多,体系结构中可能会遇到的复杂性就越高。

此外,我们将与您讨论一些定义,例如百科全书。 为什么这很重要? 因为建筑学中的术语非常重要,所以我们需要与您说相同的语言。 大部分定义来自称为OOP的编程范例。 但是实际上,它们已经发展成其他范式,它们使用术语“类,对象,接口”不仅在OOP框架内运行。 但是,这些定义和理解恰恰来自OOP领域。



最简单的是类。 什么是课程? 这是一个模板,这是一个示例。 例如,Snake类是Snake类。 我们已经为她定义了三个私有字段,即,除了类本身的方法之外,任何人都无法访问的字段-目标数,尾巴数和鹦鹉的长度。 我们确定了将这些相同的头,尾和长度放在鹦鹉中的构造函数。 上了蛇课。 一切都很简单。



我们走得更远。 对象。 对象是特定结构的实例。 而且,再次在经典的OOP中,它暗示一个对象是一个类的对象。 在现代世界中,在JavaScript中,JavaScript并非总是一种OOP语言,即使现在也不是无处不在的OOP语言,我们知道可以有抽象对象。 也就是说,我们可以创建一个对象,即文字,它不会是该类的对象。 但是,这是一个示例,说明如何创建Snake类的对象。 在这里,我们有一条长38只鹦鹉的两条尾巴蛇-大蟒蛇。



模组 模块是语义单元。 这并不总是一堂课。 它可以是一组类,一组对象,一组未组合为类的方法。 通常,您可以假定模块就是您写入单个文件的内容。 但是,原则上,模块是它们所在的文件夹,例如,该模块的文件和测试也是一个模块。 在这里重要的是,模块就是所谓的模块,即您认为是语义单元的模块。 在这种情况下,该模块是关于我们如何吃蛇的。 当我们吃蛇时,该模块的结果是最后一个方法eatSnake。 我不知道为什么我们要吃蛇,但是我们可以做到,因为我们是这样写的。



这是微不足道的,然后将开始更有趣的事情。 类接口。 一个类的接口,更简单地说,是其公共方法,它所坚持的对象,我们可以从外部的对象从该类的对象获得的内容。 此类实现getSnakeLength接口。 他可以把那条蛇的长度还给我们。 请注意,没有外部访问私有字段的权限。 从外部只能访问公共方法getSnakeLength。



然后是一件非常有趣的事情。 我们争论了很长时间该怎么称呼,因为在我创建本讲座时我创造了“抽象接口”一词。 老实说,我从未见过这种方法和方法的一般定义。 但是,许多编程语言都允许您创建抽象接口,并在没有抽象类和抽象接口的情况下立即调用它们,而只是接口。 原来是与类接口的同音字。 这个想法是抽象接口是一组执行某些操作的方法。 当我们创建一个类时,我们从“这是什么?”这个问题出发 这是一条蛇,她知道怎么做,或者不知道。 她可以尽力而为。

当我们创建界面时,我们从他所做的事情,他应该做的事情开始。 事实证明,这是扩展类的一种非常强大的方法。 我们可以将类归为某些类,并在接口的帮助下进行扩展。 例如,I-BEM框架可以做这样的事情,框架中内置了具有抽象接口的故事。 不幸的是,许多框架都不知道怎么做,而且功能强大。

在此,作为示例,我们创建了可听的界面,可以听起来。 他的定义是抽象的空getNoise方法。 我们使用可审核的类扩展了我们的蛇,实现了它的getNoise方法,并且使我们的蛇嘶嘶作响。 埃里克·弗里曼(Eric Freeman)和《设计模式》(Design Patterns)的精彩著作给了我这套例子的灵感。

现在,我们将尝试更具体地研究这些示例。



但是首先,让我们谈谈为什么需要这些示例。 这张大幻灯片在这里需要它们。 这里写的内容非常重要,我什至将其放在黄色标题栏中。 可以说是口头禅。 这是一个非常重要的原则,您在设计体系结构时需要始终考虑它。 高内聚力,低耦合-强附着力,弱连接性。 存在以下问题:将单词cohesity和coupling译成俄语,依此类推,等等,“ connectedness”被翻译,单词coupling是为此原理专门发明的。

这是主意。 您的模块必须非常紧凑,紧密耦合。 它们必须实现一个功能。 在它们之间,它们应该非常容易地连接,以便可以像设计师一样容易地组合,组装。 然后,您的架构将足够灵活且足够可靠。 而且易于测试。

让我们看看如何在所谓的要点上实现强牵引力和弱耦合。



专业化。 每个块只能解决一个问题。 在这里,我们有一个很好的例证-儿童设计师。 我们有每个区块或一组区块。 它们大小各异,大小各异。 而且,如果我们需要盖房,我们将开长酒吧。 如果我们需要打一个球,我们会打短杠。 每个条都有自己的功能。 而且那些玩过构造函数的人都知道:棋子的形状越简单,就可以从中获得更多的收益。 不会由这种zagogulin构建任何东西,或者仅构建说明中描述的东西。 谁需要它?

同样的东西,抽象。 这是关于实现中接口的抽象。 这个想法是,接口是外部的,我们的类如何,我们的块突出,它与其他块的交互方式不应影响其内部实现。 相反-它发生了。 另一种方式-永远不会。 在一个好的架构中。 在此,作为示例,这些丘疹的形成不影响块本身的形状。 我们分别选择块的形状并在其上粘贴胶水。



封装。 继续上一主题。 在私有方法中,也就是说,在我们的块中,我们意识到了我们的块,实现的意义。 接口,即它们的连接方式,是公开的。 也就是说,在这种情况下,所有这些叉号,破折号和表格本身就是实现方式。 和丘疹是接口。 好的架构看起来像这样的构造函数。



哦,多么可怕的怪物。 这是关于重用代码。 实际上,最初,这个怪物实际上只是为了展示不良建筑的示例,但请仔细观察。 他很漂亮。 此外,他显然对自己的生活感到高兴,用奇怪的双腿大力奔跑。 也许他甚至知道如何飞行,或者至少,他有美丽的蝴蝶翅膀。

有什么想法? 如果您有骆驼的实施方案和鳄鱼的实施方案,并且经理向您走来,并说您迫切需要骆驼鳄鱼。 您不会单独编写骆驼鳄鱼。 您将骆驼的主体与骆驼的整个实现分开。 抓住鳄鱼的头部,将其与鳄鱼分开,然后重新使用积木。 为什么这是必要的?

然后,当经理再次向您跑来,并说我们正在紧急扩展到南美,并且有鳄鱼时,我们需要保持不规则的颚形,或者那里的鳄鱼的第四颗牙齿不是那样,您不会对整个项目感到困惑,您在哪里复制了鳄鱼的头部。 因为您附近可能还有其他斑马野牛鳄鱼。 您只需将您的班级作为鳄鱼的头,从鳄鱼头的系列中进行扩展,为其指定参数,它将为自己确定要为其绘制牙齿的方式。 仅此而已。 在一个地方,而不是在所有使用它的地方。

在这里,可靠性有时会提高,因为在某些非常罕见的项目中,您一定会忘记一些复制的头。 总的来说,这种干部没有错。 优秀的干部,很有用。



- . , . TypeScript, . , . , , , TypeScript 2.7 , ( — . .).

, User. . . User , . User , , .

printLabel. User. , User User, . User User , , . - , .

, ? , . , . , − , UserWithSurname, , printLabel. ? , , , , . - ? , . , − , . . PrintLabel . ? ? , .

, . , . , , . , if, , . , , .



printLabel, , iPrintLabel , iPhone, . - getText. User, iPrintLabel. , , , - , getText iPrintLabel, , . UserWithSurname, User, Surname getText. printLabel . iPrintLabel getText.

, , , . . , , . , , , , , iPrintLabel, , , , − . printLabel . , .

. , , , front-end, , . , front-end , , .



-? . - back-end. - API, , REST API REST. — , − -. , , - PowerPoint, . .

front-end. Front-end - . - , . , - . . . , -, . , , . .

front-end, , , , , , , .

> - ( Client-server )
> ( Component-based )
> ( Event-driven )
> REST ( Representational state transfer )
> --*( MVC , MVP , MVVM )
> ( Flux )

这些是架构方法。 我们今天提到了其中一些。 客户端服务器架构; 组件架构,它的一种变体是React所熟悉的,希望是熟悉的。 奇怪的是,事件也是每个人都熟悉的事件,它基于几乎所有个人计算机操作系统。 REST是服务器中我们最喜欢的东西,而今天我们将详细了解的最后两个是最前端的,我们使用的是表示模型*和单向数据流。

让我们从MV *开始。 为什么是星号? 正如他们所说,历史充满着痛苦和愤怒。 曾几何时,早在80年代,就发明了MVC的出色架构方法。 M-模型,V-视图,C-控制器。 该方法非常方便。 通常是为控制台应用程序发明的。 但是,当Web技术开始发展时,当他们都开始使用它时,事实证明有时是必要的,这里的MV模型是好的,但是Controller的实现方式不正确。 结果,Model-View实现的变化如此之多-由于它全称为MVC,因此一开始就引起混淆。 因为,如果有MV模型,那么第三个是Controller,那么我们实际填充的内容并不重要。

事实证明,人们对MVC感到困惑并指的是完全不同的事情。 大约在不超过一年前的今天,他们开始积极共享此术语,并为这种方法的每种实现使用自己的名字。 一种或另一种方式,此MV *出现了。 我还在互联网上看到了MVW一词,其中W代表任何东西。 好吧,事实上,我们正在转向MVC技术。



他们如何安排? 这个想法是我们有一个存储数据的模型。 通常有很多。 有某种视图可以向用户显示此数据。 通常,它们也很多。 第三组件是它们之间的中介,它连接数据和显示。 在这里,右上角的用户可以使用所有这些功能。



MVC的创建始于1980年,Smalltalk。 但到目前为止,它是以这种形式存在于某些框架中的。 不在很多,很多。 有什么想法? 用户直接使用视图和控制器。 他将数据输入视图中的某些字段,然后按Submit(提交)按钮,然后数据将发送到控制器。 这是一个表单提交。 我希望这样一个诚实的表单通过提交按钮提交,很长时间以来大家都熟悉。

我们看。 从用户到控制器的黄色箭头-用户使用提交按钮将数据传输到控制器。 一个绿色的箭头,-控件传递到那里。 控制器查看此数据。 也许他以某种方式处理它们,实现的精妙之处已经在这里,然后将它们发送到所需的模型。 控制器本身选择要发送的模型。 发送绿色箭头,发送带有黄色箭头的数据。

该模型还处理数据。 也许她验证了它们。 也许她把它们放在了基地。 简而言之,模型知道如何处理它们。 通常,结果是新数据。 例如,我们可以告诉用户他是否登录,然后模型使用登录名检查密码。 之后,模型再次将控制权转移给控制器,以便控制器选择要显示的视图。 数据直接进入视图。 通常,如何做到这一点,模型如何将数据发送到视图?



很简单 如果控制器和模型位于后端,则模板视图位于服务器端。 通常,这就是Ruby on Rails,ASP.NET,Django的框架的排列方式,无论您在何处编写服务器端模板,并且收集到的HTML到达客户端,数据也很可能返回此方法。 这里有什么问题。 在单页应用程序中,无法构建这样的东西。 我们不断在服务器上存储数据,在服务器上存储数据,页面重新加载。 其次,完全不清楚应在何处进行客户端验证,通常来说,客户端JavaScript,AJAX以及所有这些都在这里? 因为如果我们想要快速的东西,那无处不在。 它根本无法以这种方式工作,或者无法使其更好地工作。

最后一行,这是一个有趣的故事,似乎扎根于2008年。 问题是:将业务逻辑存储在模型或控制器上的什么位置? 有人说:“我们将业务逻辑存储在控制器中,因为它很方便,立即将干净的数据发送到模型。 控制器将进行自我验证,重新检查(如果有),然后发送错误。” 有人说:“结果就是胖笨的丑陋的控制者,笨拙的笨拙的丑陋的控制者。” 他们真的很大。 他们说,业务逻辑应该在模型中,控制器应该轻薄,轻巧,可以传输数据,模型本身可以处理。 然后在第一个版本中,该模型通常只不过是数据库的API。

我认为真的如何? 实际上,您需要注意他们的任务。 如果视图与模型之间始终保持一对一的联系,那么一个视图就是一个模型,那么可以方便地在控制器中进行业务逻辑,并创建一个简单的干净模型,该模型实际上是数据库的API。 如果您的视图和模型可以重叠,并且一个视图依赖于多个模型,那么该模型可以使用多个视图,那么您可以方便地拥有许多瘦控制器并将它们按任意顺序进行乘积,而不必关心有多少个,它们仍然很小。

我必须说,在模型中使用业务逻辑,世界似乎已经赢得了第二个观点。 也就是说,这些胖笨的丑陋控制器似乎没有那么积极地使用。 信号,您可以在ASP.NET文档(该框架于2013年提出控制器中的业务逻辑)中观看。 在2014年的最新版本中-在模型中。 发生了一个非常有趣的时刻。

什么MVC有问题。 我们已经说过了,但我们会的。 由于尚不清楚如何实现客户端验证,因此进行测试是很困难的,但是很难完成,因为AJAX固定在了一边,您需要做一些事情。 他们想出了一个解决方案。 该解决方案称为MVP,是的,您可以在框架中遇到MVP,并且文字是MVC。 例如,骨干MVP框架。 在2011-2012-2013年的同一文档中,关于他很长一段时间的信中写道,这是一个MVC框架。



模型视图呈现器。 他的方案已经简单得多。 有型号。 他们彼此互动。 他们将数据提供给Presenter,Presenter将其传输到视图,并显示给用户。 再回来 用户将某物驱动到视图中,单击按钮,Presenter外观,AJAX发送到模型或放入模型,然后AJAX模型发送到服务器。 也就是说,一切都已经更加简单和线性了,但是如果没有服务器端标准化,那就已经很困难了。 如果您想要一台服务器,那么这样的系统将会很复杂。



让我们比较一下。 让我们看一下第一张图片,在这里我们将尝试实现一个非常简单的事情-将数据从输入发送到模型。 我们输入了一些内容,单击了一个按钮,它应该出现在模型中,模型将对此进行处理,并告诉我们发生了什么。 我们开车进入:“我的名字叫Vasya”,点击确定。 如果我们要进行客户端验证,那么它会在这里发生,几乎是通过拦截,在特别严重的情况下,实际上是通过拦截click。event.preventDefault()。 在某个地方,客户端验证的一侧为零。

然后,我们诚实地通过提交表单将数据发送给控制器。 数据进入模型,模型将其放入自身,过程和外观。 告诉我们,很好,该数据已被接受,您确实是Vasya。 第三个箭头-控件转到控制器,模型告诉控制器,请显示标签“我的名字是Vasya”。 控制器选择适当的视图,显示标签。 模型将数据输入“我的名字是Vasya”,第四个箭头,黄色。 问题是如何测试呢? 仅快照。 没有别的办法了。 甚至没有编写功能测试的内容。

第二个选项,已经带有MVP。 我们开了“我的名字叫Vasya”,点击确定。 第一箭(绿色)下的箭头-管理权交给Presenter。 主持人说:按钮被按下。 演示者看起来,第二个箭头,蓝色,请注意这是一个数据请求。 在经典MVP中,不是从视图向Presenter发送数据,而是从Presenter请求数据。 这样更干净,因为例如Presenter可能已经提前知道,它不需要数据,同样,一切都不好。

接下来,关于Presenter的第三段是诚实的JS验证。 我们已经可以安全地编写它了,这是它的一个特殊地方。 第四个箭头-数据进入模型,例如,将其放入数据库中,并说:“一切都井井有条,我将其放入。” 您会看到第五个箭头是带状的,我希望它很明显是黄绿色的,并且管理和数据都返回给Presenter。 该模型说“我放了”,Presenter意识到,由于数据已放入数据库中,因此这就意味着有必要显示一切都按顺序排列,数据已经放入。 第六个箭头-他们将其发送到视图,也许是另一个视图,但是后来我没有绘制第二个视图。

这里有什么好处。 JS验证应有尽有,一切都变得很好,AJAX也应有尽有,这可能是第四个箭头,例如,如果模型在服务器上,或者模型AJAX本身已到达服务器。 最后,我们可以安全地测试Presenter,并在其上编写功能测试。



其次,除了简化的测试之外,我们还能从正面得到什么? 我们将视觉显示与其工作分开。 也就是说,我们仍然可以在View上编写快照,并且可以在Presenter上单独编写测试。 我们可以修复Presenter而不触摸View,反之亦然。 我们的专业水平有所提高。 这就是如何安排早期版本的框架,例如Angular1,Backbone,Ember,Knockout。 一旦有很多,那就是激烈的竞争。

有什么特点。 Presenter已经放置在客户端上,可以在其中放置模型,并且可以安静地制作单页应用程序。 它发生得更好,但是这个故事有很多单页应用程序,或者至少是以前做过的。 AJAX服务器交互很好。 客户验证到位。 似乎一切都很好,为什么还要进一步考虑?

但是,至少发明了MVVM。 也是一件有趣的事情。



本质上,这是使用该框架的Presenter的实现。 当您编写第一个Presenter,第二个Presenter,第五个Presenter时,经常会发现它们都是相同的。 他们只是编织视图和模型。 如您所见,它的构建类似于MVP。



因此,许多框架刚刚解决了这些绑定任务。 有什么优势? 我们不需要编写额外的代码。 它确实加快了开发速度。 有什么缺点。 Model和ViewModel之间的连接性得到增强。

即,正是由于强连接性而在那里出现问题,因此有时会发生不使用MVVM的情况。 例如,我个人熟悉i-BEM框架中的MVVM,我们有时使用但有时不使用它,因为这是一种不方便的,过于严格的绑定。 但是,Microsoft Silverlight就是通过这种技术来安排的,他们说:很好。 我不知道,我还没有尝试过。

为什么发生了,除了MVP和MVVM之外,还出现了一些其他问题,大家都熟悉redux一词,为什么还有单向数据流。



我们看正确的图片。 我们拥有MVP的人经常会有这样的问题。 假设我们有一个复杂的系统,而不是一对一的-许多视图,许多模型。 它们都是相互连接的。 上面的视图(黄色)更改了模型。 该模型已更改另一种模型。 底部的黄色视图已更改。 下部视图也改变了模型。 所有这些一起改变了中央红色视图,并且其中发生了一些不可理解的事情。

当他们由于弹出未读消息而不断出现错误时,Facebook面临着这种情况。 即,用户看到“您有未读消息”,但没有打开。 因为两个视图一起纠正了该视图的状态,所以...通常,从两个不同的来源纠正了视图的状态,不清楚谁是对的。 他们裁定,再次出现错误,再次裁定,再次出现错误。 最后,他们很累,他们决定从根本上解决问题,对这些重言式感到抱歉,只是使视图状态具有确定性。

MVP的问题恰恰是系统状态的不确定性。 我们不能总是预测她现在的状况,谁先到那里,谁纠正了什么。 正如他们所说,助焊剂通过遗传学解决了这个问题。 他不能那样。 他们在这里很长时间以来一直在告诉我,采用单向数据流的想法是真的。 当然,这个概念是在Facebook之前,2013年他们发布之前就发明的。 但是,正如他们所说的那样,他们已经申请了专利,他们首先发布了一个散文集,我们想出了这样的东西,请使用它。



让我们更详细地了解Flux。 这是主意。 我们有一个商店,而这个商店是一个数据仓库,这是我们应用程序的唯一真实来源。 其他一切都不真实。 他如何工作? 首先,如果我们专门研究工作周期,通常是从用户开始做某事开始,即视图正在工作。 视图创建一个动作。 请注意,“动作”未填写在图片中。 为什么这样 因为它是一个结构。 这不是一个类,不是一个对象,也不是什么聪明的东西。 这就是结构。 在Web上,我们可以用JavaScript编写它,它就是那个非常抽象的对象。

该视图创建一个结构,并传递给块管理器。 块管理器触发回调。 也就是说,他说:“调用Action发生时被告知要调用的函数。 他说给商店打电话。 即,从调度程序中调用Store方法。 该方法被调用。 该方法被调用,它是在Store上获得的。 商店会查看所发生的事情,以某种方式自身发生变化。 他正在改变自己的状况。 而且他是唯一可以改变自己状况的人。 没有人这样做。 也就是说,他是真理的唯一来源。 之后,它将广播到与之相关的所有视图以及与之相关的所有组件:“我已经改变了,去获取数据。”

视图用于数据,然后一个有趣的时刻开始。 在经典的Flux中(例如在Facebook上),视图将完全重绘。



这是带有标签和按钮的表格。 她如何工作? 我们看点零。 零点也在这里。 他是回调注册最底部的蓝色箭头。 这是首先发生的事情。

商店经理打来电话:“请注册我的回调,当Action出现时我该怎么办。” 发生了 然后,我们可以使用该应用程序。 我们单击了一个按钮,创建了一个结构。 请注意,除了用户输入的数据(例如Vasya)外,Action还具有元数据类型。 非常重要的一点是,Action本身传达的是哪种Action,但无论如何都向调度员传达。 他抛出了所有的动作广播。 第一个箭头,该方法被调用。

调度程序实际上调用了一个方法触发器,然后将其传递给该方法。 在Action触发器上,将调用一个回调,该回调在零点处注册。 这是红色箭头,这是来自回调的回调调用。 商店获取了这些数据,看起来类型是更改名称,所以我在名称字段中将自己更改为Vasya,然后将其发送到后端,并以某种方式验证了,通常来说,商店知道该怎么做。 接下来,紫色箭头将广播更改事件。 我们已经改变了。 每个人都知道我们已经更改了商店。

接下来,是经典Flux的一个小功能,对于使用Redux的人(甚至是使用React而不是Redux的人)可能不熟悉。 视图用于数据。 他们去商店说:“我有这个领域,这个领域和这个领域。” 相反,我们已经习惯了这样一个事实,那就是,如果您使用React,Redux或类似的东西,那么一切都会出现在视图中。 第六点,彻底重画。

让我们看一下该图并找到瓶颈,因为什么? 重绘。 彻底重画,这就是为什么Flux在2013年之后开始被积极使用的原因是什么时候出现的? 是什么使这成为可能? 虚拟房子。 虚拟房屋,仅在确实需要时才允许您重绘。



让我们暂且谈谈React,像React这样成功地将它与Flux结合在一起,使人们知道了该技术最受欢迎时的世界。

相同的2013,相同的2013,相同的Facebook。 最初,React一般是作为MVC,MVP,变体中的视图通知而发明的。 确实可以在那里使用它。 它的力量是什么。 首先,正如他们正确地说的那样,虚拟房屋不允许重绘真实房屋,因为这是一项非常困难的操作,而是允许重绘虚拟房屋。 而且只有在确实发生了更改的情况下,我们才重新绘制该组件,结果一切运行得比可能快得多。

并且-纯不可变的组件。 这是属性机制。 该实现也是反应式的,允许您创建不具有其自身状态的组件。 而且,如果您使用这种体系结构编写代码,那么创建无状态,无状态的组件是非常正确的。 他们只有来自商店的数据,然后由他绘制。 它们方便测试,很少损坏。 静态是很难破解的,测试很容易。

结合Flux架构的应用程序功能强大。 可能很多人都知道这确实是一个有力的事情。 必须提到什么重要意义? 除了React Redux,还有许多其他捆绑包。 您可能知道第二个Angular。 它也是反应框架和Flux架构的结合。 Vue, Flux Redux — Fluxxor, MobX . . React Redux. Vue, , , React Redux. .



? , React Redux . Vue, . — . — MVC-. . . - React Redux .

MVP/MVVM- . , — , , . single page application, multiple page application. - - . , -, - . , MVP, .

— single page application , , . . Flux React Redux, View, Angular, MobX, Fluxxor . .

. .

> MVC: Smalltalk-80 , General MVC , ASP.NET , MVC on Web
> MVP: MVP vs MVC , GUI Architecture , Backbone , Angular1
> MVVM: MS Silverlight , i-BEM
> Flux: Hexlet , Flux for stupid people , Flux official , ReactJS , VueJS
> : , «Javascript. » , ., « » , D.Garlain, M.Shaw, ”An introduction to Software Architecture” (1994), E.Dijkstra ”GOTO statement considered harmful” (1968)

MVC, MVP, MVVM . , . Flux . , , . , — . . JavaScript. . ES5, «JavaScript. » , ES6- — , , , .

, « ». . Java, . , , Flux, . MVP, — -. , . .

, , « ». , , , , , . «GOTO operator considered harmful». . , .

. . . , - , . , , Flux, , input Flux. — , , - . . , . , . .

Source: https://habr.com/ru/post/zh-CN425611/


All Articles