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

xds2000 · 2013年12月11日 · 最后由 winnie 回复于 2013年12月17日 · 22503 次阅读
本帖已被管理员设置为精华贴

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 是否满足 多功能按钮执行的需求?

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