分享 DHH 再次重申,Rails 项目应该拥抱 SJR,别去整啥 JSON-Client render 方案。

xds2000 · 2013年12月11日 · 最后由 winnie 回复于 2013年12月17日 · 21077 次阅读
本帖已被设为精华帖!

Server-generated JavaScript Responses https://37signals.com/svn/posts/3697-server-generated-javascript-responses

这绝对是最强音的逆袭。你如果没点耐性,就直接接受吧。👍

Revised: 经过吕哥提醒,是 SJR,不是 RJS。但我怎么觉得这是一回事啊。。。。

DHH 一点气度没有,对比一下 prototype.js 作者呼吁大家用 jQuery

我也非常赞同应该 RJS

  1. 重点还是 partial 复用,RJS 和普通 View 共用一个 partial,如果用 JS,那些复杂的结构还得一个个绑定,另外有些 helper 的方法还得在 JS 里面实现一下;
  2. 用 JS render 不一定会比后端生成 HTML 快;

我的感觉就是,最好用一套,如果选择了 rjs 就最好多用吧。。。 但是我想说,如果是用了 js mvc 还需要 rjs 吗?

这是 SJR 不是 RJS 啊

#2 楼 @huacnlee 赞同。尤其是 partial 的复用。。

简单可靠的方式

Benefit #2: Less computational power needed on the client

说实话看到这条我觉得 DHH 是在逆历史潮流而动

#7 楼 @edokeh

那是另外一种做法,和 DHH 说的不冲突

我感觉 AngularJS 类的 JavaScript MVC 框架 正在馋食 Rails 的地盘

最近在用 Angular ,感觉 Rails 里面大部分组件已经不需要了(View/Helper 等),只需要提供 JSON 就行 当然这会出现 DHH 第一点里说的那个问题,JS & JSON 加载未完成时首页出不来,但是为此做一个特殊的优化并不是难事

还从没正儿巴紧整过 RJS 。最大的问题应该是测试吧,js 东一团西一团,要测也只能上 selenium 这样重要级的东西。

#7 楼 @edokeh 当带宽越来越宽后,减少 client 的消耗会是潮流了。毕竟以后的手持设备需要更合理的使用电量,这是硬件瓶颈,很难很快突破。而且在 server 端容易做缓存,在给多 client(一人多台设备)分发时,计算资源的节省是可见的。

这跟气度和潮流无关,Rails 本质上还是 server side 的解决方案,走的还是服务端处理大部分逻辑的路子。这种情况下某些 ajax 请求返回 html + js partial 确实比直接返回 json 更好。不需要一套 template 分别用 erb 和 js 实现两份(尤其是 template 中含有数据格式化的,更蛋疼)。可以最大程度的重用代码,易于维护,也方便打 cache。

照 SJR 的思路发展,turbolink 的出现就是一种必然了。对不是非常重客户端交互的应用来说,Rails 提供的这种解决方案还是挺好的。提供一定的动态交互的同时最大限度的利用 Rails 在 view 那一层优势。

但如果用前端 MVC 的话,因为 template 的逻辑都在客户端,这时候 json 就是最好的选择。因为 server 已经完全没有必要关心数据怎么展示的问题了。

总之,一件事情,要么前端做,要么后端做。两边都做 50% 的话非常夹生…… 如果两边都做 100% 那就蛋疼了。

#7 楼 @edokeh 这当然是顺潮流, 计算一定是越来越多在服务端, 在网速越来越快的情况下, client 端最后应该是只负责显示

#14 楼 @larryzhao 对于 Web 来说,这么多年的发展难道不是将计算能力从 Server 推向 Client ? 否则 Chrome 和 V8 为什么要出现?胖客户端的趋势是很明显的啊

#13 楼 @darkbaby123 这个说的详细,完全赞同,Turbolink 就是一种 “夹生” 的方案 过份点说,叫 “不伦不类”

SJR 总代码量其实是最少的. DHH 最后一段也说了, 如果是很复杂的客户端 MV* UI, 就不要用了

同意 darkbaby123 的看法,json 绝对是最好的选择,而且客户端 js 分发得是完整的应用逻辑,这件事情非常重要。

#2 楼 @huacnlee 赞同 个人感觉 RJS 用起来省心一些,而且更 MVC 一些,之前也没有深入思考这个问题,只因为用 RJS 简单。

我觉得这玩意儿还是不能一概而论, 看你做的是啥和当时的情况.

对于一个 Single Page Application, 如果要我不要用 Backbone/Spine/Ember, 而是用 SRJ, 我觉得会做起来困难很多。相应的比如简书的阅读文章的页面, 我不可能用前端 MVC 来实现, 人家到了这个页面就是想要立刻看到内容的, 不现实先载入整个 MVC 框架, 完成初始化, 再等待 json 回来做内容填充, 你就算相应时间再快, 用户刷页面还是会看到 html 填充的过程, 所以这部分肯定是一个正常的 page render, 相应的所涉及的一些 Ajax, 就很自然的会用到 SRJ.

虽然我用很多 SRJ, 我感情上还是略微倾向于 json + 前端 render, 也可能是因为一些'洁癖'的关系吧, 当然 SRJ 可以复用 partial 的好处是极大的, 但用下来一直以来的感觉我觉得还是有一些不好的地方的:

  • 由于 javascript 是一个 response, 没那么容易在 inspector 里进行调试
  • 如果是 render partial, 整个替换掉某一块的 html, 类似用 turbolink, 对 javascript 本身处理流程有影响, 个人觉得代码逻辑会没那么通顺.
  • javascript 不是和 javascript 写在一起, 显得很乱, 如果写在一起应该能更好的管理和任务分配
  • SRJ 用 coffee 很痛苦, 只能前面用 coffee, SRJ 用 javascript.

#2 楼 @huacnlee

文中举例的 create.js.erb 这种写法,我以前也试过,但总觉得不舒服。原因是,本来我的 callback 全部写在 CoffeeScript 中,现在要将 call back 分离写在一个 erb/js 文件中。代码就不集中在一齐了,请问你感觉是如何的?

后面的两种解决方法,感觉都不大好,但能用。

  1. 返回 JSON,然后用 JS 的 Template render 就是 DHH 反对的方案 (这个上面已有讨论)

  2. 直接在后端 render partial template,然后 JS 获取后在依业务改变页面数据。

还用,如果用 create.js.erb,部分 JS 就不能 precompile 了,也不能用 CoffeeScript。总觉得 JS, erb 混写很恶心,我的 vim 都认不出来。

#15 楼 @edokeh 因为你说的这个是 '社会主义初级阶段', 是必须经历的过渡阶段。

代码分散在不同的 erb 里 弊端太大 fat client 才是历史潮流

#22 楼 @larryzhao 我大概明白你的意思,但是单就 Web 或者叫 B/S 来看,计算能力确实是从 Server 慢慢流向 Client,或者说,B/S 越来越像 C/S

#24 楼 @edokeh 还是那句话, 这是为了在当下获得最佳体验的中间过渡阶段.

想象一下, 如果云端计算量足够大, 网络带宽和相应时间都理想化, 一切都是跟 stream 超清视频一样, 那所有应用都是直接打开可用, 下载什么客户端, load 什么 js, 我们的设备只需要薄薄的一块屏幕用以显示和接受操作就好了. 如果 3D 游戏的每一帧都可以 stream 过来, 还搞什么 WebGL 呢.

科幻电影里那些整面墙全部可以随处点随处玩, 肯定不会是整面墙都在计算, 只需要显示就可以了.

凡是 DHH 支持的都是对的 ...

两个凡是都出来了

业务逻辑永远也只能放在 Server,js-app 的 controller 不是控制业务逻辑,是控制页面逻辑。

如果一个 site 经常需要大改版的话 我觉得 DHH 的方案是好的, SPA 做维护比 RJS 花的时间多的多

SJR Server-generated Javascript Response

根据不同的团队,不同的需求,可以选择不同的解决方案 大公司大厂,各种人才齐备,api service 一个团队,网站后端一个团队,前端一个团队,完全可以用复杂的方案 对于小团队小项目,人少又要快速开发,可能这种方案比较方便快速。

#21 楼 @MaFai

create.js.erb 仅仅会是很简单的东西

# 找到对应 DOM xxx
# Render partial 准备好需要渲染的内容
# xxx.append(content) 或 xxx.replace(content)

比如 Ruby China 的 app/views/replies/create.js.erb

<% if @reply.errors.blank? %>
  <% @page = 1 %>
  $("#replies .items").append('<%= j(render("reply", :reply => @reply, :reply_counter => @topic.replies_count - 1, :display_edit => true)) %>')
    .find(".total b").text('<%= @topic.replies_count %>');
    $("#replies .reply a.edit:last").css("display","inline-block");
    Topics.replyCallback(1,'<%= j(@msg) %>');
<% else %>
  Topics.replyCallback(0,'<%= j(@msg) %>');
<% end %>

#17 楼 @luikore 表示用 XSLT 才是最少的,不需要再另外维护一套 API 了,从简单到复杂普遍适用,速度也快。

#35 楼 @huacnlee 感觉会是下一个 Bug 重灾区。

#38 楼 @huacnlee 感觉啊,需要多重 escape 的地方来点小魔法什么的最容易出 Bug 了

以前我也向往过 client side,看过 angular 和 ember 的文档,但是真正动手的时候就怂了,将渲染移到 client side,意味着原本每个小查询都要写成 API,例如分类列表。而要减少远程调用,加快第一页速度,就要写 init 逻辑,把要用的数据塞到页面 js。最后为了 seo,还要单独写一份简化版的服务端渲染(discourse.org)。一般的 CRUD 用 client side 方案真是麻烦很多。

客户端的计算能力提升,可以用去需要客户端做的事上,例如拍照、定位、动态图表、编辑器等等,而要给移动应用写 API,可以单独写 API 接口,不跟网站混在一起。

所以,我赞成 DHH 的方案。

#40 楼 @Rei 试过 clouda 么?

#12 楼 @beenhero 有道理的。举个最简单的例子,很多 mobile browser 在滚动条滚动时会完全禁掉 javascript 。这可能是出于节能的考虑。

如果我没有理解错的话,Angular,ember,backbone 之类的本来就是要抛弃 rails 的,rails 当然对他们离的远的一点

#40 楼 @Rei 我认为两种技术各有各的市场,纯 client 渲染,实际上就是一个 web app,已经和传统意义上的 web 不是一回事了,举个例子,weibo 里的 chat,你可以使用纯 client 渲染,也可以使用 rjs 之类的技术渲染,但那种更优雅,不言而喻。当然这种纯 client 渲染的方案并不是到处到适用,例如你的那个网站 writing.io,我认为传统的服务端渲染更好,不知道我的这种看法怎么样。

#44 楼 @xwf286 为啥?我的应用前端用的 b/m,后端还是 rails 啊,只是没有用 rails 的 view,感觉还是很好用的。。。

神翻譯

#46 楼 @hooopo 哦。。。原来这里有讲

其实嘛,我觉得,网站用 dhh 这种,web app 用 js mvc 就好,但是问题就是,一般都是先有个站,最后才衍生出 app,所以就蛋疼的最后加个 api 目录搞 app.... 哎。。。

真的有那么多 Fat Client 么?内容还是最主要的呀..

@Victor 如此本土化的翻译,完美表达了 DHH 的嚣张样~

SJR 的项目测试怎么做?有开源的项目使用 SJR 的吗?

53楼 已删除

#45 楼 @xwf286 web chat 就像 DHH 最后提的 basecamp 日程表,适用 client side。basecamp 整体是 server side,部分功能用 client side。

用的js.erb的感觉就是:小项目还好,大项目那 js 简直是凌乱的不忍直视。

这是以前说过的话题吧,其实是 REST 和 MVC 两种不同的架构之间的矛盾造成的,这个问题上没有标准答案,只能看情况——团队的知识结构和应用的复杂度

目前越来越多的项目都是 restful 后台,然后 web 端弱化成一个普通的 client 端. 这样做规模越大越得力, 数据和逻辑都是后台, 前台负责本地化展现, api 级别是 restful 的,利于扩展.

对于 native app,这么做貌似阻力不大,对于 web 的话, 能熟练使用 js 并做测试的人实在太少了,所以接受的难度肯定要大不少. 而且 SEO 之类的问题也比较头疼.

我个人是赞同将计算力向客户端迁移的, 当然前提是应用要足够成功, 越成功的应用, 越多计算放在客户端,则需要的服务器维护费用会越少, 当用户量超过 10w 以上的时候, 差距应该会越来越明显. 善用 browser cache, server side cache 等等也是减少 cpu,io 量的一个办法,但是都不如仅仅拿 JSON 那么节省 bandwidth 和计算力.

@xds2000 RJS 是很早以前(Rails 3 以前)Rails 推出的用 Ruby 写 JavaScript 的方法,完全是 Ruby 代码

举个栗子:

# some_view.rjs
page['time_updated'].replace_html Time.now
page.visual_effect :highlight, 'the_list'

这段代码是从 这篇 ITEye blog 上摘抄的,看看日期你就知道有多古老了。

Rails 会把这一段代码渲染成 JavaScript,当时还是使用的 Prototype。年代太久远记不清楚了,大概是这个样子:

$('time_update').replace('some time');
$('the_list').visualEffect('highlight');

这种技术非常依赖前端的 JavaScript 库,而且也不够直观。只不过算是一种 “用 Ruby 写任何东西” 的理念的衍生物。

后来在 Yehuda 把 RJS 移除了(貌似是 Rails 3 时代?),换成了 js.erb 的方式,直接在 view 里面写 JavaScript。这就是 DHH 文章里面说的 SJR(Server generated JavaScript Responses)。

@xds2000 话说我怎么觉得这帖子标题有点像新闻联播?比如 “XXX 再次重申 XX 自古以来都是中国不可分割的一部分……”

重客户端 JSON 轻客户端 SJR

#58 楼 @darkbaby123 原来是 Yehuda 把 RJS 移除的,估计他也是觉得现在的 SJR 还是太蹩脚,然后直接投身到 Ember 的开发了 😄

@HungYuHei 如果他还没走说不定 Rails 就直接变成 API server 了……

@small_fish__ 那还不如直接 grape

如果是一个本身就是前端出身的人肯定给出的是完全不一样的看法。

sjr 在我看来无法前后端分工开发,两种语言混写出错率高。

普通网站带上少量 ajax 可以用 sjr,真正的 web app 还是得看 angular,ember,knockout 之类的

@small_fish__ 反正我现在是没用的,就是 Rails + Ember 。因为我还是用的 Devise 的 session 验证。虽然有办法去跟 Rails API 结合,但我还需要 sprocket ,懒得折腾了。 其实 Rails API 就是个减去了不必要 middleware 的 Rails,其他地方没什么区别。

@small_fish__ BTW 作为 Rails API 依赖的一部分,active_model_serializers 貌似也是有 Yehuda 参与的。它默认生成的 json 格式和 Ember Data 是吻合的,不过现在有点不一样了。

#32 楼 @Victor Enjoy: "颤抖吧凡人。"。。。 #40 楼 @Rei 同感,虽然目前程序的 ajax 不少,erb.js 的代码颇不顺眼,但是想到那么多逻辑重写和 SEO 的问题,还是怂了。一个问题或许解决了,但是又需要解决那么多新问题。我觉得还不如将精力放在程序本身的逻辑优化重构上。

#35 楼 @huacnlee 谢回复,知道你的看法了。我不喜欢这种写法,不过我同意这种写法是最简便的,以前我试过采取 render 某个 attribute,再由 JS 去依据做不同的行为,来替换像这种混写的 SJR。

SJR 是没问题,但是感觉 LZ 太标题党了点。

@darkbaby123 是 DHH 标题党,和我没关系啊。

#12 楼 @beenhero

毕竟以后的手持设备需要更合理的使用电量,这是硬件瓶颈,很难很快突破。

前几天刚有新闻说实现常温超导体……然后移动设备最省电的使用方式是客户端缓存数据后离线使用……

74楼 已删除

好处 #1: 重用模板且不牺牲性能 Angular 可以重用 Rails 的 局部模板,任何后缀都可以

不能显示任何东西, 直到你的整个 JavaScript 库都加载完毕 Angular 可以先显示 html 模板,局部用 loading,让用户先看到页面。

你需要执行两次动作 (一次是服务器端的 first-response, 一次是客户端的 subsequent-updates) 如果是简单页面,一次执行即可,ng-init 可以接受初始化数据 如果是复杂的,有重用模板的页面,可以用传统 Rails 的方式重用模板。

服务器端生成模板通常可以缓存并在多用户间共享 DHH 说的是页面片断缓存,而 模板缓存 + 数据缓存 一样解决问题,而且不混乱。

从 end-to-end 的角度发送 JavaScript+HTML 有可能比 JSON 配合客户端生成模板更快。 客户端生成模块?有时候根本不需要重新生成模板,DHH 真的应该看看 ng-repeat 如果是调用新模板, 两次 Ajax 请求 + 客户端计算 VS 一次 Ajax 请求 + 服务器端计算 前者服务器性能要求更低,后者少一次请求数,但是这是在用户交互时,相差约等于 0

浅显易懂的执行流程 老式 Form action 是否满足 多功能按钮执行的需求?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册