单页应用:优点和缺点

我读过关于SPA和它的优点。 我发现他们中的大多数不能令人信服。 有三个好处,引起我的怀疑。

问题: 你能否作为SPA的倡导者,certificate我对前三句话的错误?

=== ADVANTAGES === 

1. SPA非常适合非常敏感的网站:

服务器端渲染很难实现所有的中间状态 – 小视图状态不能很好地映射到URL。

单页面应用程序的特点是能够重画UI的任何部分而无需往返服务器来检索HTML。 这是通过将数据与数据表示分离来实现的,具有处理数据的模型层和从模型读取的视图层。

拿着非SPA的模型图层有什么问题? SPA是否是唯一与客户端MVC兼容的体系结构?

2.使用SPA,我们不需要额外的查询服务器来下载页面。

哈,用户在访问您的网站时可以下载多less页? 二三? 相反,会出现另一个安全问题,你需要将你的login页面,pipe理页面等分成不同的页面。 反过来又与SPA架构冲突。

可以有其他的好处吗? 别听任何其他的..

  === DISADVANTAGES === 
  1. 客户端必须启用JavaScript。
  2. 只有一个入口点的网站。
  3. 安全。

PS我从事过SPA和非SPA项目。 我正在问这些问题,因为我需要加深我的理解。 没有意思伤害SPA支持者。 不要要求我多阅读一下SPA。 我只是想听听你的考虑。

我们来看看最受欢迎的SPA网站之一GMail。

1. SPA非常适合非常敏感的网站:

服务器端的渲染并不像以前那样使用简单的技术,比如在URL中保留一个#hash,或者更近的HTML5 pushState 。 通过这种方法,网页应用程序的确切状态被embedded到网页的URL中。 和Gmail一样,每次打开邮件时,都会在URL中添加一个特殊的哈希标签。 如果复制并粘贴到其他浏览器窗口可以打开完全相同的邮件(只要他们可以进行身份​​validation)。 这种方法直接映射到一个更传统的查询string,区别仅在于执行。 使用HTML5 pushState(),您可以消除#hash并使用完全经典的URL,这些URL可以在第一个请求上在服务器上parsing,然后在后续请求中通过ajax加载。

2.使用SPA,我们不需要额外的查询服务器来下载页面。

用户在访问我的网站期间下载的页面数量? 当他/她打开他/她的邮件帐户时,真的有多less个邮件读取。 我一口气读了> 50。 现在邮件的结构几乎是一样的。 如果您将使用服务器端渲染scheme,则服务器将在每个请求(典型情况)上渲染它。 – 安全问题 – 你应该/不应该为pipe理员/login保留单独的页面,这完全取决于你的网站的结构,例如,做网站SPA也不意味着你打开所有的端点用户我的意思是我使用表单身份validation与我的水疗网站。 – 在可能最常用的SPA框架Angular JS中,开发者可以从网站加载整个html寺庙,这样可以根据用户authentication级别来完成。 为所有authtypes预加载html不是SPA。

3.可能还有其他什么好处? 别听任何其他的..

  • 这些日子里,你可以安全地假设客户端将启用JavaScript的浏览器。
  • 只有一个网站的入口点。 正如我前面提到的状态维护是可能的,你可以有任意数量的入口点,但你应该有一个确定的。
  • 即使是SPA用户也只能看到他有什么权利。 你不必一次注入所有的东西。 加载diff html模板和javascript async也是SPA的有效部分。

我能想到的优点是:

  1. 渲染HTML显然需要一些资源现在每个访问你的网站用户正在这样做。 现在不仅渲染主要逻辑现在已经完成了客​​户端而不是服务器端。
  2. date时间问题 – 我只是给客户端UTC时间是一个预先设定的格式,甚至不关心我让JavaScript处理它的时区。 这对我不得不根据从用户IP获得的位置来猜测时区的地方是非常有利的。
  3. 对我来说状态更好地维护在一个SPA,因为一旦你设置了一个variables,你知道它会在那里。 这给人一种开发应用程序的感觉,而不是网页。 这通常有助于制作诸如foodpanda,flipkart,amazon等网站。 因为如果你不使用客户端状态,你正在使用昂贵的会话。
  4. 网站肯定是非常敏感的 – 我会举一个极端的例子来尝试在非SPA网站上制作一个计算器(我知道它很奇怪)。

缺点

1.客户端必须启用JavaScript。 是的,这是SPA的一个明显的缺点。 在我的情况下,我知道我可以指望我的用户启用JavaScript。 如果你不能那么你不能做SPA,期间。 这就像试图将.NET应用程序部署到未安装.NET Framework的计算机上。

2.只有一个入口点的网站。 我使用SammyJS解决了这个问题。 2-3天的工作才能正确设置路由,人们将能够在您的应用中创build正确工作的深层链接书签。 您的服务器只需要公开一个端点 – “为此应用程序提供HTML + CSS + JS”端点(将其视为预编译应用程序的下载/更新位置) – 您写的客户端JavaScript处理实际进入应用程序。

3.安全。 这个问题并不是独一无二的,当你有一个“老派”客户端 – 服务器应用程序(HATEOAS使用超文本链接页面模型)时,你必须以完全相同的方式处理安全问题。 只是用户正在提出请求,而不是您的JavaScript,而且结果是HTML而不是JSON或某种数据格式。 在非SPA应用程序中,您必须保护服务器上的各个页面,而在SPA应用程序中则必须保护数据端点。 (而且,如果你不想让你的客户端访问所有的代码,那么你必须将可下载的JavaScript拆分成不同的区域,我只是简单地把它和我的基于SammyJS的路由系统绑定,这样浏览器只会请求客户知道它应该有访问权限,基于用户angular色的初始负载,然后这就成为一个没有问题的事情。)

优点

  1. 在许多情况下,SPA(很less被提及)的一个主要的体系结构优势就是应用程序的“讨厌”程度大大降低。 如果你正确地devise它来处理客户端上的大部分处理(毕竟,整个点),那么对服务器的请求数量(读取“503错误的可能性,破坏你的用户体验”)大大减less。 事实上,SPA可以完成离线处理,这在某些情况下是非常重要的

  2. 如果你做得对,客户端渲染的性能肯定会更好,但这不是build立SPA的最有说服力的理由。 (毕竟,networking速度正在提高。)不要仅仅在这个基础上提出SPA。

  3. 您的UIdevise的灵活性可能是我发现的另一个主要优势。 一旦我定义了我的API(使用JavaScript中的SDK),我能够完全重写我的前端,除了一些静态资源文件外,对服务器没有任何影响。 尝试使用传统的MVC应用程序! :)(当你有API的实时部署和版本一致性时,这会变得很有价值。)

所以,底线:如果您需要脱机处理(或者至less希望您的客户能够偶尔发生服务器中断) – 显着降低您自己的硬件成本 – 并且您可以假设JavaScript和现代浏览器,那么您需要一个SPA。 在其他情况下,这更多的是权衡。

我是一个实用主义者,所以我会试着从成本和收益的angular度来看待这个问题。

请注意,对于我给予的任何不利条件,我承认它们是可以解决的。 这就是为什么我不看黑白,而是看成本和收益。

优点

  • 更容易的状态跟踪 – 无需使用cookie,表单提交,本地存储,会话存储等来logging2页加载之间的状态。
  • 每个页面(页眉,页脚,徽标,版权横幅等)上的锅炉板内容仅在每个典型的浏览器会话中加载一次。
  • 切换“页面”没有开销延迟。

缺点

  • 性能监控 – 双手绑定:大多数浏览器级别的性能监控解决scheme我只看到了页面加载时间,比如第一个字节的时间,DOM的build立时间,HTML的networking往返,onload事件等。更新页面通过AJAX后加载不会被测量。 有一些解决scheme可以让你testing你的代码来logging明确的措施,比如点击一个链接,启动一个计时器,然后在渲染AJAX结果后结束一个计时器,然后发送这个反馈。 例如New Relic支持这个function。 通过使用SPA,你只能将自己绑在一些可能的工具上。
  • 安全/渗透testing – 双手绑定:当您的整个页面由SPA框架dynamic构build时,自动安全扫描可能难以发现链接。 有可能的解决scheme,但是,你已经限制了自己。
  • 捆绑:在初始页面加载下载整个网站所需的所有代码时,很容易出现这种情况,对于低带宽连接来说,这可能会非常糟糕。 你可以绑定你的JavaScript和CSS文件,试图加载更自然的块,但现在你需要维护这个映射,并监视意外的文件,通过未实现的依赖关系(只发生在我身上)拉入。 再次,可以解决,但成本。
  • 大爆炸重构:如果你想做一个重大的架构改变,比如说,从一个框架切换到另一个框架,为了最大限度地降低风险,最好进行增量更改。 也就是说,开始使用新的,在某种基础上迁移,比如每页,每个function等等,然后放弃旧的。 使用传统的多页面应用程序,您可以将一个页面从Angular切换到React,然后在下一个Sprint中切换另一个页面。 随着SPA,这是全部或没有。 如果你想改变,你必须一次性改变整个应用程序。
  • 导航的复杂性:工具的存在有助于维护SPA中的导航上下文,如history.js,Angular 2,其中大部分依赖于URL框架(#)或更新的历史API。 如果每个页面都是一个单独的页面,则不需要这些。
  • 搞清楚代码的复杂性:我们很自然地把网站想成页面。 多页面的应用程序通常按页面分区,这有助于可维护性。

我再一次认识到,这些问题中的每一个都是可以解决的,而且是有代价的。 但是有一点你花时间解决问题,你可能刚刚避免摆在首位。 它回到了对他们的好处和重要性。

SPA – SEO的一个主要缺点。 直到最近,Google和Bing都在抓取过程中通过执行JavaScript来开始索引基于Ajax的页面,而且在很多情况下页面被错误地编入索引。

在开发SPA时,您将被迫处理SEO问题,可能是通过后期渲染您的所有网站并为抓取工具创build静态html快照。 这将需要对适当的基础设施进行坚实的投资。

更新19.06.16:

由于前一段时间写这个答案,我获得了单页面应用(即AngularJS 1.x)的更多经验 – 所以我有更多的信息可以分享。

在我看来,SPA应用程序的主要缺点是search引擎优化,使他们仅限于种类的“仪表板”应用程序。 另外,与传统的解决scheme相比,你的caching将要困难得多。 例如,在ASP.NETcaching中非常容易,只要打开OutputCaching就可以了:整个HTML页面将根据URL(或任何其他参数)被caching。 但是,在SPA中,您将需要自己处理caching(通过使用二级caching,模板caching等一些解决scheme)。

对于像谷歌,亚马逊等公司,其服务器在24/7模式下以最大容量运行,减lessstream量意味着真正的金钱 – 硬件less,能源less,维护less。 从服务器到客户端的CPU使用率的转移是有好处的,而且SPA也在闪耀。 迄今为止超重的缺点。 所以,SPA还是非SPA在很大程度上取决于用例。

只是提到另外一个,对于Web开发人员来说可能不那么明显(用于Web开发人员):我正在寻找一种在embedded式系统中实现GUI的方法,而基于浏览器的体系结构似乎对我很有吸引力。 传统上,embedded式系统中的用户界面并不多,例如Java,Qt,wx等,或者商业框架。 几年前,Adobe试图用闪光灯进入市场,但似乎并没有那么成功。

如今,由于“embedded式系统”与几年前的大型机一样强大,通过REST连接到控制单元的基于浏览器的UI是一个可行的解决scheme。 好处是,免费的UI工具的巨大的调色板。 (例如,Qt需要20-30美元每单位的专利使用费加上每个开发商3000-4000美元)

对于这样的体系结构,SPA提供了许多优势 – 例如桌面应用程序开发人员更熟悉的开发方法,减less服务器访问(通常在汽车行业,UI和系统混乱是单独的硬件,其中系统部分具有RT OS)。

作为唯一的客户端是内置的浏览器,所提到的缺点,如JS可用性,服务器端日志logging,安全性不再计算。

我希望将SPA作为数据驱动应用程序的最佳select。 gmail当然是关于数据的,因此是SPA的一个很好的候选人。

但是如果你的页面大多是用来显示的,例如一个服务条款页面,那么一个SPA是完全矫枉过正的。

我认为最好的地方是有一个网站混合了SPA和静态/ MVC风格的页面,具体取决于页面。

例如,在我正在构build的一个站点上,用户login到一个标准的MVC索引页面。 但是当他们去实际的应用程序,然后调用SPA。 另一个好处是,SPA的加载时间不在主页上,而是在应用程序页面上。 主页上的加载时间可能是第一次站点用户的分心。

这种情况有点像使用Flash。 经过几年的经验,由于负载因素的原因,仅Flash网站的数量下降到接近零。 但作为页面组件,它仍在使用中。

2.使用SPA,我们不需要额外的查询服务器来下载页面。

我仍然需要学习很多东西,但自从我开始学习SPA以来,我就喜欢它们。

这一点可能会产生巨大的差异。

在很多不是SPA的networking应用程序中,您将会看到他们仍然会检索并添加内容到发出Ajax请求的页面。 所以我认为,SPA超越了以下考虑:如果将使用ajax检索和显示的内容是整个页面,该怎么办? 而不只是一个页面的一小部分?

让我来介绍一个场景。 考虑你有2页:

  1. 一个包含产品列表的页面
  2. 一个页面查看特定产品的详细信息

考虑你在列表页面。 然后你点击一个产品来查看细节。 客户端应用程序将触发2个Ajax请求:

  1. 一个请求得到一个JSON对象与产品的细节
  2. 请求获取产品详细信息将被插入的HTML模板

然后,客户端应用程序将数据插入到HTML模板并显示它。

然后你回到列表(没有请求完成这个!),你打开另一个产品。 这一次,只会有一个Ajax请求来获取产品的详细信息。 HTML模板将是相同的,所以你不需要再次下载。

您可以说在非SPA中,当您打开产品详细信息时,您只提出一个请求,在这种情况下我们做了2个。是的。 但是,从整体angular度来看,当你浏览多个页面时,获得的收益将会更低。 而且在客户端和服务器之间传输的数据也将会更低,因为html模板将被重用。 此外,您不需要下载每个请求中的所有这些CSS,图像,所有页面中存在的JavaScript文件。

另外,让我们考虑你的服务器端语言是Java。 如果你分析了我提到的2个请求,1个下载数据(你不需要加载任何视图文件,并调用视图渲染引擎)和其他下载和静态html模板,所以你可以有一个HTTP Web服务器,可以检索它直接无需调用Java应用程序服务器,不需要计算!

最后,大公司正在使用SPA:Facebook,GMail,亚马逊。 他们不玩,他们有最伟大的工程师学习这一切。 所以,如果你没有看到你最初可以信任的优点,并希望在路上发现它们。

但使用良好的SPAdevise模式非常重要。 你可以使用像AngularJS这样的框架。 不要试图在没有使用好的devise模式的情况下实施一个SPA,因为你最终可能会陷入混乱。

缺点 :从技术上讲,SPA的devise和初步开发是复杂的,可以避免的。 不使用这个SPA的其他原因可以是:

  • a)安全性:由于跨站点脚本(XSS),单页应用程序与传统页面相比不太安全。
  • b)内存泄漏:JavaScript中的内存泄漏甚至可能导致强大的计算机放慢速度。 由于传统网站鼓励在页面间导航,因此前一页导致的内存泄漏几乎被清除,留下的残留更less。
  • c)客户端必须启用JavaScript才能运行SPA,但是在多页面应用程序中JavaScript可以完全避免。
  • d)SPA增长到最佳尺寸,等待时间过长。 例如:使用Gmail连接速度较慢。

除此之外,其他架构限制还包括导航数据丢失,浏览器中没有导航历史logging以及使用selenium进行自动functiontesting的困难。

此链接解释单页应用程序的优点和缺点。

如果没有首先定义如何解决服务器端的安全性和API稳定性问题,不要考虑使用SPA。 那么你会看到使用SPA的一些真正的优势。 具体而言,如果您使用实现OAUTH 2.0的RESTful服务器来实现安全性,那么您将实现两个基本的问题分离,可以降低您的开发和维护成本。

  1. 这会将会话(以及它的安全性)移到SPA上,并免除您的服务器的所有开销。
  2. 你的API变得稳定和容易扩展。

暗示较早,但没有明确表示; 如果您的目标是部署Android和Apple应用程序,那么编写一个由本地调用包装的JavaScript SPA以便在浏览器(Android或Apple)中托pipe屏幕,无需同时维护Apple代码库和Android代码库。

在我的发展中,我发现使用SPA有两个明显的优势。 这并不是说传统的networking应用程序无法实现以下function,只是看到了增量利益而没有引入额外的缺点。

  • 更less的服务器请求作为呈现新内容的可能性并不总是或者甚至不是用于新的html页面的http服务器请求。 但是我说潜力是因为新的内容很容易需要Ajax调用来提取数据,但是这些数据可能会比本身更加轻量,加上标记提供了一个净效益。

  • 维护“国家”的能力。 用最简单的话来说,在进入应用程序时设置一个variables,在整个用户体验中,其他组件都可以使用该variables,而不必将其传递给本地存储模式。 智能地pipe理这个能力是保持顶级范围整洁的关键。

除了要求JS(这不是一个疯狂的事情要求的Web应用程序)其他指出的缺点是在我看来不是特定于SPA或可以通过良好的习惯和发展模式缓解。

我知道这是一个较老的问题,但我想添加单页应用程序的另一个缺点:

如果您构build以数据语言(如XML或JSON)而不是格式化语言(如HTML)返回结果的API,则可以实现更大的应用程序互操作性,例如,在企业对企业(B2B)应用程序中。 这样的互操作性有很大的好处,但是确实允许人们编写软件来“窃取”(或窃取)你的数据。 对于所有使用数据语言的API而言,这种特殊的缺点是普遍的,而不是一般的SPA(实际上,向服务器请求预先呈现的HTML的SPA避免了这种情况,但代价是模型/视图分离不佳)。 这个缺点所暴露的风险可以通过各种方式来减轻,如请求限制和连接阻塞等。