单页应用程序:优点和缺点

IT技术 javascript 建筑学 客户端 单页应用程序
2021-01-31 10:44:15

我已经阅读了 SPA 及其优势。我发现他们中的大多数都没有说服力。有3个优点引起了我的怀疑。

问题: 您能否作为 SPA 的倡导者并证明我前三个陈述是错误的?

                              === ADVANTAGES ===

1. SPA 非常适合响应迅速的网站:

服务器端呈现很难为所有中间状态实现 - 小视图状态不能很好地映射到 URL。

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

为非 SPA 持有模型层有什么问题?SPA 是客户端唯一与 MVC 兼容的架构吗?

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

哈,用户在访问您的网站时可以下载多少页?二三?相反,出现了另一个安全问题,您需要将登录页面、管理页面等分成单独的页面。反过来,它与 SPA 架构相冲突。

3.可能有什么其他优点?不听别的..

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

PS我从事过 SPA 和非 SPA 项目。我问这些问题是因为我需要加深我的理解。无意伤害SPA支持者。不要让我多读一点关于 SPA 的内容。我只是想听听您对此的看法。

6个回答

让我们看看最受欢迎的 SPA 站点之一,GMail。

1. SPA 非常适合响应迅速的网站:

使用简单的技术(例如在 URL 中保留 #hash 或最近的HTML5 )pushState,服务器端呈现不像以前那么难通过这种方法,Web 应用程序的确切状态被嵌入到页面 URL 中。在 GMail 中,每次打开邮件时都会在 URL 中添加一个特殊的哈希标签。如果复制并粘贴到其他浏览器窗口可以打开完全相同的邮件(前提是它们可以进行身份​​验证)。这种方法直接映射到更传统的查询字符串,区别仅在于执行。使用 HTML5 pushState(),您可以消除#hash并使用完全经典的 URL,这些 URL 可以在第一次请求时在服务器上解析,然后在后续请求中通过 ajax 加载。

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

用户在访问我的网站时下载的页面数??当他/她打开他/她的邮件帐户时,他/她实际上阅读了多少邮件。我一口气读了> 50。现在邮件的结构几乎相同。如果您将使用服务器端渲染方案,则服务器将在每个请求(典型情况)上渲染它。- 安全问题 - 您应该/不应该为完全取决于您网站结构的管理员/登录保留单独的页面,例如 paytm.com 也制作网站 SPA 并不意味着您打开所有端点用户 我的意思是我在我的 spa 网站上使用表单身份验证。- 在可能最常用的 SPA 框架 Angular JS 中,开发人员可以从网站加载整个 html 寺庙,以便可以根据用户身份验证级别来完成。为所有身份验证类型预加载 html 是'

3. 可能还有什么优势?不听别的..

  • 如今,您可以放心地假设客户端将拥有支持 javascript 的浏览器。
  • 网站只有一个入口点。正如我之前提到的,状态维护是可能的,您可以根据需要拥有任意数量的入口点,但您肯定应该拥有一个。
  • 即使在 SPA 用户中,也只能看到他拥有的适当权利。你不必一次注入所有东西。加载 diff html 模板和 javascript async 也是 SPA 的有效部分。

我能想到的优点是:

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

评论更新

似乎没有人提到套接字和长轮询。如果您从另一个客户端注销,比如移动应用程序,那么您的浏览器也应该注销。如果不使用SPA,则每次出现重定向时都必须重新创建套接字连接。这也应该适用于数据中的任何更新,例如通知、配置文件更新等

另一种观点:除了您的网站,您的项目是否会涉及原生移动应用程序?如果是,您很可能会从服务器(即 JSON)向该本地应用程序提供原始数据并进行客户端处理以呈现它,对吗?所以有了这个断言,你就已经在做一个客户端渲染模型了。现在问题变成了,为什么不应该为项目的网站版本使用相同的模型?有点没脑子。那么问题就变成了您是否只想为了 SEO 的好处和可共享/可收藏的 URL 的便利性而呈现服务器端页面

您无法使用 SPA 轻松索引页面以进行 SEO 优化。
2021-03-25 10:44:15
@Parv Sharma 请更广泛地解释为什么保持状态与 SPA 更兼容?
2021-03-31 10:44:15
@Ankit_Shah55 这可能不再正确(至少对于拥有大部分搜索引擎市场份额的谷歌而言)。请参阅 Google 的“弃用我们的 AJAX 抓取方案”。我的理解是,您不必再为 Google 做任何特别的事情来索引您的 SPA。但是,我认为您需要确保支持 pushstate,因为我不认为 google 索引哈希片段。
2021-04-06 10:44:15
很高兴您将其作为社区 Wiki 答案:) 这些也是很好的观点
2021-04-07 10:44:15
似乎没有人提到套接字和长轮询。如果您从另一个客户端注销,比如移动应用程序,那么您的浏览器也应该注销。如果不使用SPA,则每次出现重定向时都必须重新创建套接字连接。这也适用于任何数据更新,如通知、配置文件更新等。
2021-04-08 10:44:15

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

请注意,对于我给出的任何劣势,我承认它们是可以解决的。这就是为什么我不把任何事情看成非黑即白,而是看成本和收益。

好处

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

缺点

  • 性能监控 - 束手无策:我见过的大多数浏览器级性能监控解决方案都只关注页面加载时间,比如第一个字节的时间、构建 DOM 的时间、HTML 的网络往返、onload 事件等。 更新页面不会测量通过 AJAX 的后加载。有一些解决方案可让您检测代码以记录显式度量,例如单击链接时,启动计时器,然后在呈现 AJAX 结果后结束计时器,并发送该反馈。例如,New Relic 支持此功能。通过使用 SPA,您只需要使用几种可能的工具。
  • 安全/渗透测试 - 束手无策:当整个页面由 SPA 框架动态构建时,自动安全扫描可能难以发现链接。可能有解决方案,但同样,您已经限制了自己。
  • 捆绑:当您在初始页面加载时下载整个网站所需的所有代码时,很容易陷入这种情况,这对于低带宽连接可能会非常糟糕。您可以捆绑您的 JavaScript 和 CSS 文件,以便在进行时尝试以更自然的块加载,但现在您需要维护该映射并注意通过未实现的依赖项引入的非预期文件(这恰好发生在我身上)。同样,可以解决,但需要付出代价。
  • 大爆炸重构:如果您想进行重大的架构更改,例如从一个框架切换到另一个框架,以最大程度地降低风险,则需要进行增量更改。也就是说,开始使用新的,在某些基础上进行迁移,例如每页、每功能等,然后删除旧的。使用传统的多页面应用程序,您可以将一个页面从 Angular 切换到 React,然后在下一个冲刺中切换另一个页面。有了 SPA,一切皆有可能。如果要更改,则必须一口气更改整个应用程序。
  • 导航的复杂性:存在工具来帮助维护 SPA 中的导航上下文,例如 history.js、Angular 2,其中大部分依赖于 URL 框架 (#) 或更新的历史 API。如果每个页面都是一个单独的页面,则您不需要任何页面。
  • 计算代码的复杂性:我们很自然地将网站视为页面。多页应用程序通常按页对代码进行分区,这有助于可维护性。

再一次,我认识到这些问题中的每一个都是可以解决的,但需要付出一定的代价。但是到了某个时刻,您将所有时间都花在解决您本来可以避免的问题上。回到好处以及它们对您的重要性。

我认为此回复提供了来自实际构建大型复杂系统并经历过 SPA 带来的长期伤亡(或看起来如此)的人的非常有效的反馈
2021-03-15 10:44:15
我直接经历了最后4个劣势点。我已经使用 Angular、Bootstrap 和 PHP 作为主要参与者构建了一个 10K LOC 的 Web 应用程序,其中包含大约 5K 的 Angular JS 代码。Angular 有一些非常简洁的功能,但在这一点上,我真的希望我刚刚使用了一种传统的基于页面的方法,我认为它会显着加快网站的开发速度。
2021-03-24 10:44:15
我从这个答案中得到的是,如果您正在做任何非常严肃的事情,请避免使用 SPA。
2021-03-26 10:44:15
我同意。当我们进行概念验证时,SPA 看起来很棒。3 年过去了,我们已经看到了这个答案中提到的每一个问题,我们将继续花费大量时间来尝试解决这些问题。框架更改不再是一种选择,我们坚持使用一个基本上停止开发的框架。
2021-04-01 10:44:15
@Prometheus 我仅在应用程序的 REST API 部分的后端使用 PHP(通过 Slim 框架)。SPA 部分是用 Angular 构建的。
2021-04-03 10:44:15

缺点

1. 客户端必须启用javascript。是的,这是 SPA 的一个明显缺点。就我而言,我知道我可以期望我的用户启用 JavaScript。如果你不能,那么你就不能做 SPA,期间。这就像尝试将 .NET 应用程序部署到没有安装 .NET Framework 的机器上。

2. 站点只有一个入口点。我使用SammyJS解决了这个问题需要 2-3 天的时间才能正确设置您的路由,并且人们将能够在您的应用中创建正确运行的深层链接书签。你的服务器只需要公开一个端点——“给我这个应用程序的 HTML + CSS + JS”端点(把它想象成预编译应用程序的下载/更新位置)——你编写的客户端 JavaScript 将处理进入应用程序的实际入口。

3. 安全。这个问题不是 SPA 独有的,当您拥有“老式”客户端-服务器应用程序(使用超文本链接页面的 HATEOAS 模型)时,您必须以完全相同的方式处理安全问题。只是用户发出请求而不是您的 JavaScript,结果是 HTML 而不是 JSON 或某种数据格式。在非 SPA 应用程序中,您必须保护服务器上的各个页面,而在 SPA 应用程序中,您必须保护数据端点。(而且,如果您不希望您的客户端访问所有代码,那么您也必须将可下载的 JavaScript 拆分为单独的区域。我只是将其绑定到基于 SammyJS 的路由系统中,以便浏览器仅请求根据用户角色的初始负载,客户端知道它应该有权访问的内容,

好处

  1. 在许多情况下,SPA 的主要架构优势(很少被提及)是大大减少了应用程序的“健谈”。如果您正确设计它以处理客户端上的大多数处理(毕竟是重点),那么对服务器的请求数量(阅读“破坏用户体验的 503 错误的可能性”)将大大减少。事实上,SPA 使得完全离线处理成为可能,这在某些情况下巨大的

  2. 如果操作正确,客户端渲染的性能肯定会更好,但这并不是构建 SPA 的最令人信服的理由。(毕竟网络速度正在提高。)不要仅在此基础上就为 SPA 辩护。

  3. UI 设计的灵活性可能是我发现的另一个主要优势。一旦我定义了我的 API(使用 JavaScript 中的 SDK),除了一些静态资源文件之外,我能够完全重写我的前端,对服务器的影响为零尝试使用传统的 MVC 应用程序来做到这一点!:)(当您需要担心 API 的实时部署和版本一致性时,这变得很有value。)

所以,最重要的是:如果您需要离线处理(或者至少希望您的客户能够在偶尔的服务器中断中幸存下来)——显着降低您自己的硬件成本——并且您可以假设使用 JavaScript 和现代浏览器,那么您需要一个 SPA。在其他情况下,这更多是一种权衡。

另一个优点是 SPA 可以在 iOS 上保存为书签(“添加到主屏幕”),并在全屏模式下打开(假设您定义了正确的元标记),让它感觉像一个本地应用程序,而不是一个网页。
2021-03-15 10:44:15
SO 的 SPA 版本是否可以提供指向要共享的单个问题的链接,或者它会带来哪些优点和缺点,例如在 SEO(搜索引擎的过去问题的可搜索性)方面。
2021-03-31 10:44:15
3.在传统的MVC应用程序中同样简单。如果您使用相同的数据进行操作,您只需要在应用程序的 V(视图)部分进行更改。这通常是模板、css 和 js。
2021-04-06 10:44:15
我见过的大多数 SPA 应用程序都比服务器端应用程序更健谈。您最终会在每页上向服务器发出更多请求,而不是单个请求来获取数据。
2021-04-10 10:44:15

SPA 的一大缺点 - SEO。直到最近,Google 和 Bing 才开始通过在抓取过程中执行 JavaScript 来索引基于 Ajax 的页面,但在许多情况下,页面仍被错误地索引。

在开发 SPA 时,您将被迫处理 SEO 问题,可能是通过对所有站点进行后期渲染并创建静态 html 快照以供爬虫使用。这将需要对适当的基础设施进行可靠的投资。

19.06.16 更新:

自从不久前写下这个答案以来,我在单页应用程序(即 AngularJS 1.x)方面获得了更多的经验 - 所以我有更多的信息要分享。

在我看来,SPA 应用程序的主要缺点是 SEO,使它们仅限于“仪表板”应用程序。此外,与经典解决方案相比,您将在缓存方面遇到困难得多的时期。例如,在 ASP.NET 中缓存非常简单 - 只需打开 OutputCaching 即可:整个 HTML 页面将根据 URL(或任何其他参数)进行缓存。但是,在 SPA 中,您需要自己处理缓存(通过使用一些解决方案,如二级缓存、模板缓存等)。

@MarsAndBack:不确定您在谈论哪个服务器链接。如果您的意思是站点地图 - 那么它在 SPA 的情况下没用:搜索引擎不执行 JavaScript(至少,这是几年前的状态),它们只下载和解析 HTML。因此,即使您准备了站点地图 - 页面也不会正确构建。
2021-03-21 10:44:15
我不明白 SEO 的论点。难道你不能在你的 SPA 中定义相同的路由也定义服务器端,这样搜索机器人可以轻松地抓取你的网站,同时人们可以获得你内容的直接 URL。因此,您可能需要维护两套模板,这很重要。如果有这样的问题,您可以尝试使用通用模板。
2021-03-26 10:44:15
将流量转发到单个页面与分布在几个页面上是否更好的 SEO?
2021-04-07 10:44:15
@SILENT - 不确定,但由于所有页面都在同一个域中,我认为应该没有区别
2021-04-07 10:44:15

我想说明 SPA 最适合数据驱动应用程序。gmail 当然是关于数据的,因此是 SPA 的一个很好的候选者。

但是,如果您的页面主要用于显示,例如服务条款页面,那么 SPA 就完全是矫枉过正了。

我认为最好的地方是拥有一个混合了 SPA 和静态/MVC 样式页面的站点,具体取决于特定页面。

例如,在我正在构建的一个站点上,用户登陆标准 MVC 索引页面。但是当他们进入实际应用程序时,它会调用 SPA。另一个优点是 SPA 的加载时间不在主页上,而是在应用程序页面上。主页上的加载时间可能会分散第一次访问站点的用户的注意力。

这个场景有点像使用 Flash。经过几年的经验,由于负载因素,仅 Flash 站点的数量下降到接近于零。但是作为一个页面组件,它仍然在使用。

这也是我的方法。我将 SPA 作为我的用户快速翻阅搜索结果的主要区域,无论是地图还是动态列表。然后在查看详细信息时,这些将作为标准的服务器渲染页面打开。我的路由既可以在 SPA 中使用,也可以作为首次加载的服务器路由使用。我复制了模板代码和路由代码,但我不在乎,这是一个必要的邪恶。
2021-03-25 10:44:15
经过多年的网络开发,这是我可以确认的。您应该将 spa 和 mvc 应用程序混合在一起。你也无法得到答案。我首先将我的整个应用程序用作水疗中心,发现我的应用程序没有被谷歌正确列出。所以我搬到了 mpa 并仅在需要的情况下使用 spa。wordpress 也不是 spa 和流行的框架,这是有充分理由的。
2021-04-05 10:44:15