【问题标题】:Rendering javascript at the server side level. A good or bad idea?在服务器端渲染 javascript。好主意还是坏主意?
【发布时间】:2010-05-18 14:56:59
【问题描述】:

现在是一个社区维基!

我想先说清楚:这不是关于服务器端 Javascript 或运行 Javascript 服务器端的问题。这是一个关于从服务器端代码呈现 Javascript 代码(将在客户端执行)的问题。

话虽如此,以下面的 ASP.net 代码为例:

hlRemoveCategory.Attributes.Add("onclick", "return confirm('Are you sure you want to delete this?');")

这是在服务器端规定客户端 onclick 事件。

反对在客户端写Javascript:

$('a[rel=remove]').bind('click', function(event) {
    return confirm('Are you sure you want to delete this?');
}

现在我想问的问题是从服务器端代码呈现 javascript 有什么好处?反之亦然?

我个人更喜欢将客户端 UI/行为与 HTML 元素挂钩的第二种方式,原因如下:

  • 服务器端已经完成了它需要做的任何事情,包括数据验证、事件委托等;和
  • 服务器端视为事件的内容不一定与客户端的进程相同。即,客户端有更多事件(只需查看自定义事件);和
  • 在一个事件期间,客户端和服务器端发生的事情,可能完全不相关和解耦;和
  • 客户端发生的任何事情都发生在客户端,服务器没有需要知道。服务器应该处理并运行给他们的东西,如果发生客户端事件,流程如何实现并不是由他们来决定的;以此类推。

这些显然是我的想法。我想知道其他人的想法,以及是否有关于这个话题的任何讨论。

从这个参数分支的主题可以到达:

  • 代码管理:从服务器端渲染所有内容是否更容易?
  • 关注点分离:如果将客户端逻辑与服务器端逻辑分离会更容易吗?
  • 效率:无论是编码还是运行,哪个效率更高?

归根结底,我正试图让我的团队转向第二种方法。这支球队中有很多老家伙害怕这种变化。我只是想用正确的事实和统计数据说服他们。

让我知道你的想法。

UPDATE1:看来我们所有参与过这篇文章的人都有共同的想法;很高兴知道还有其他想法相似的人。现在去说服这些人;)谢谢大家。

【问题讨论】:

  • 这应该是社区维基,因为人们显然是根据他们的意见对答案进行投票,而不是根据信息的正确性。
  • 正如你在我的新手徽章上看到的,我不知道。我会看看如何把它变成一个社区维基。感谢您的信息 =)

标签: asp.net javascript jquery server-side serverside-javascript


【解决方案1】:

您的第二个示例远优于第一个示例。 Javascript 是您的行为层,应该与您的语义标记(内容)和 CSS(表示)分开。这是更好的架构有很多原因:

  • 鼓励渐进增强。正如您所提到的,后端代码应该在没有 JS 的情况下正常工作。你不能依赖你的客户有可用的 JS。这样你就可以在没有 JS 的情况下构建一次,然后可以增强那些使用 JS 的体验(例如,通过添加客户端验证和服务器端验证,以便客户端可以获得即时反馈)
  • 更清晰的标记。通常会减小下载大小。一个单独的 JS 文件中的可重用选择器,可以在页面之间缓存和共享,而不是每个元素上的处理程序。
  • 您的所有 JS 都在一个重复使用的地方。例如如果您的代码正在打开一个弹出窗口,并且您决定更改窗口的尺寸,您只需在 JS 文件的代码中更改一次即可,而不必在每个单独的内联处理程序上更改它。

还有很多其他的论点和原因,但它们应该能让你开始......

此外,从您的示例看来,您的文档中有一个可以删除内容的普通链接。这也是一个不好的做法。任何删除或更新内容的操作都应在 POST(而不是 GET)请求中完成。所以应该是提交表单的结果。否则例如googlebot 可能会通过抓取您的页面而意外删除您的所有内容(搜索引擎机器人不会执行 JS,因此您的警报在那里无济于事)

【讨论】:

    【解决方案2】:

    我能想到的两个最大的区别是:

    • 如果 javascript 在单独的 js 文件中,您会丢失客户端缓存
    • 如果您需要更改 javascript,则必须重新编译(将此推断为发布产品后发生的情况:如果必须重新编译,则需要重新分发二进制文件,而不仅仅是修改后的 js 文件)
    • 如果 javascript 在单独的文件中,使用 VS 调试器会更容易;您可以在该文件中设置一个断点,如果您正在生成代码服务器端,那么您必须使用运行文档功能,找到您生成的代码然后添加断点,并且每次您都必须手动添加断点重新- 运行您的应用程序。接下来,如果代码位于单独的文件中,那么您只需调整 javascript 代码,F5 浏览器页面,并继续调试,而无需停止并重新启动调试器。

    应该提到,有时您必须从服务器插入 js 代码 - 例如,如果您的大部分代码位于单独的 js 文件中,并且您需要在页面中插入控件标识以使该代码可以使用.尽量避免这种情况。

    【讨论】:

    • RE:控件标识 - 现在,使用 jQuery 等框架,在客户端识别控件是一件非常容易的工作。通过 css 类属性或任何其他自定义属性,例如 data-tooltip="true"(显然在非 XHTML 页面上)。我个人更喜欢自定义属性,因为它提供了更多的灵活性。我完全同意您关于为小的客户端更改重新编译代码的观点!太烦人了。
    【解决方案3】:

    看来您已经知道该怎么做了。在服务器端渲染它是个坏主意。

    简单的推理是您是 Javascript 既存在于服务器端页面上,也存在于单独的 Javascript 文件中(假设您使用的是 Javascript)。当一切都无处不在时,修复问题可能成为调试的噩梦。

    除了服务器端脚本生成的内容之外,如果您没有使用任何其他 Javascript,它可能会很好且易于管理(忘记不显眼的动作是怎么说的)。

    其次,如果页面上有 100 个链接,您将在 100 个位置重复相同的代码。重复是另一个维护和调试的噩梦。您可以使用一个事件处理程序和一个属性来处理所有页面上的所有链接。这甚至不需要再考虑。

    <Rant>

    将 HTML 和 Javascript 甚至 CSS 分开并不容易,特别是如果您想要一些 AJAX 或 UI 优点的话。为了实现完全分离,我们必须迁移到桌面应用程序模型,在该模型中,所有前端代码生成在客户端以编程方式使用 Javascript,all 与服务器仅限于纯数据交换。

    大多数上游通信(客户端到服务器)已经只是数据交换,而不是下游通信。许多服务器端脚本生成 HTML,将其与数据合并并返回。只要服务器控制生成 HTML 视图就可以了。但是,当花哨的 Javascript 出现并开始将行附加到表中时,并且通过精确复制现有 HTML 结构为 cmets 附加 div,然后我们创建了生成标记的两个点。

    $(".comments").append($("<div>", {
        "id": "123",
        "class": "comment",
        "html": "I would argue this is still bad practice..."
    }));
    

    也许这不是一场噩梦(取决于规模),但它也可能是一个严重的问题。现在如果我们更改 cmets 的结构,则需要在两个地方进行更改 - 最初生成内容的服务器端脚本和模板,以及在页面加载后动态添加 cmets 的 Javascript 端。

    第二个例子是关于使用拖拽的应用程序。如果您可以在页面周围拖动 div,则需要将它们从常规页面流中取出,并使用精确的坐标进行绝对或相对定位。现在,由于我们无法预先为所有可能的坐标创建类(尝试这样做很愚蠢),我们基本上直接在元素中注入样式。我们的 HTML 如下所示:

    &lt;div style="position: absolute; top: 100px; left: 250px;"&gt;..&lt;/div&gt;

    我们把漂亮的语义页面搞砸了,但必须这样做。

    &lt;/Rant&gt;

    抛开语义和行为分离,我想说基本上归结为重复。您是否不必要地重复代码。是否有多个层处理相同的逻辑。是否可以将所有这些都推到一个层中,或者减少所有重复。

    【讨论】:

    • 很好的咆哮。再补充一点:即使(服务器端)生成的 JavaScript 代码是动态的并且取决于应用程序状态,分离到不同的 .js 文件并使用 JSON 将服务器端变量导出到页面 -javascript 是比生成更好的解决方案每个分支都有不同的代码。
    【解决方案4】:

    您和其他回答问题的人已经列出了为什么最好不要让服务器端代码将内在事件属性吐到文档中的原因。

    硬币的另一面是这样做是快速简单(至少在短期内)。

    IMO,这并没有超过该方法的缺点,但这是一个原因。

    【讨论】:

      【解决方案5】:

      对于您示例中的代码,这并不重要。该代码没有使用任何仅在服务器端可用的信息,因此在客户端代码中绑定事件同样容易。

      有时您想使用服务器端可用的一些信息来决定是否应该添加事件,或者为事件创建代码,例如:

      if (categoryCanBeDeleted) {
        hlRemoveCategory.Attributes.Add(
          "onclick",
          "return confirm('Are you sure you want to delete the " + categoryType + "?');"
        );
      }
      

      如果您要在客户端执行此操作,则必须以某种方式将此信息放入页面中,以便客户端代码也可以访问它。

      【讨论】:

      • 我认为这仍然是不好的做法。相反,您应该设置例如元素上的 css 类并在客户端选择器中使用它或者像问题中的原始代码一样,您只能将 rel 设置为删除应该删除的链接(在我的回答中需要注意删除任何内容无论如何都来自 GET 链接)
      • 为此我喜欢 HTML5 中的数据属性。您可以在元素本身上嵌入消息。例如:&lt;a data-delete="true" data-warning="Are you sure you want to delete your account permanently?"&gt;Delete Account&lt;/a&gt;。然后 Javascript 可以获取所有具有data-delete 属性的元素,并使用高度可定制的嵌入消息。 Rails 3 在这样的事情上押下大赌注来减少 Javascript 的混乱。
      • 我同意 vitch 和 Anurag 的观点。我认为这篇文章已经有很多例子了。
      • @davidhong:是的,我知道你的意见,但你询问了其他人的想法。看来我想错了……
      • 不同之处在于我们已经成功地探索了选项并且至少在这部分得出了结论。所以没有人错,我们都获得了知识=)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 2011-03-06
      • 2011-10-26
      • 2010-11-23
      • 2015-07-20
      • 1970-01-01
      相关资源
      最近更新 更多