引见 Rails 4.0 的 Turbolinks

介绍 Rails 4.0 的 Turbolinks

介绍 Rails 4.0 的 Turbolinks

David Heinemeier Hansson, Ruby on Rail创始人,最新在 Twitter 发布 上发布一个叫做Turbolinks的新功能,会在Ruby on Rails 4.0版本的Gemfile默认绑定发布。Turbolinks 已经在手机网站Basecamp发挥了巨大作用。

一些人在黑客新闻中发布了一个Turbolinks在Github的库连接,标题为

Turbolinks for Rails (like pjax)

那么,什么是PJAX,还有Turbolinks跟PJAX有什么不同?

Javascript pushState

HTML5在Javascript加入了一些新的API,其中一个就是History interface。pushState允许Javascript在会话历史中随意储存数据,并且绑定一个标题和可选的URL。back()和forward()方法允许我们浏览已存储的会话历史数据。通过这个方法,我们可以使用pushState保存当前页的浏览历史,并且动态的在不同状态下,后退和前进,而不需要重新载入整个页面。

PJAX是一个混合词,代表terms push State and AJAX。PJAX的理念其实很简单:当点击一个超链接的时候,不需要重载整个页面,而是加载页面中需要更新的某些元素。这明显需要客户端Javascript的帮助,发送一个AJAX请求到服务器,获取数据,并替代页面中需要更新的元素。

PJAX data flow diagram

使用PJAX的数据流程

上面的草稿图给我们介绍了PJAX实际是如何工作的。首先(1)一个正常的GET请求被发送到服务器,然后服务器会返回整个页面 (2). 所有连续的请求 (3)通过点击超链接而触发,但只获取页面的某些元素(4)。

在客户端,定义了一个容器 (这个例子里面,就是#mainin),当超链接‘/author’被点击的时候,容器将会被替换。

$.pjax({url:'/authors',container:'#main'})

定义PJAX动作

PJAX同样需要服务器端的应用只返回页面的某些元素。所以,PJAX在HTTP头添加了一个叫X-PJAX的请求,让web应用知道,这个请求是来自PJAX。在Rails里面,你只需简单的检查HTTP头部并赋值render :layout => false.

ifrequest.headers['X-PJAX']
render:layout=>falseend

禁用PJAX的布局请求

还有一个方法,在Rails中使用PJAX。这个方法在Ryan Bates的Railscasts Episode #294中已经得到大概的描述。PJAX也存在缺点,当你需要仔细考虑页面的哪些部分需要被替换掉。

Turbolinks同样使用pushState,但是它并不是至替代页面的某些部分,而是从服务器加载整个网页,并替换当前加载的DOM中的<title>和<body>节点。默认情况下,页面所有的链接都遵循这个规则。所以,不像PJAX,你不需要为了让链接和容器取支持重载而去标记它们,Turbolnks会帮你处理这个些问题。

现在,Turbolinks还处于开发的初期,但是就像前面提到的,它已经在Basecamp中使用。在你的Ruby(Sinatra, Rails)工程中使用,只需简单的向你的用用中添加Turbolinks的gem:

gem'turbolinks'

向你的Gemfile中添加turbolinks

不要忘记了在编辑过Gemfinle后运行bundle install来安装gem。你需要在asset pipeline中的app/assets/javascripts/application.js添加一行turbolinks.js.coffeefile

//= require turbolinks

把turbolinks包含在asset pipeline之中。


从现在开始,所有的请求将支持pushState,并由turbolinks来处理。那些不支持pushState的浏览器也可以正常工作,因为它们只需把它们当做普通的链接动作。你可以通过打开浏览器的开发者工具(Chrome里面是F12),并打开网络标签,以便检查程序是否工作正常。你会看到,在你点击了链接的时候,turbolinks.js帮你处理这这些请求。

Developer console in Chrome showing TurbolinksChrome的开发者终端显示Turbolinks如何工作

如果你需要手工的排除一些链接,不让Turbolinks帮你处理这些请求,你可以添加data-no-turbolnk属性到链接标签里面。

<ahref="/articles" data-no-turbolink>Articles</a>

手工的排除链接。

这样就可以告诉turbolinks忽略这些链接。你可以在任何容器中添加这个属性,甚至是<body>标签,Turbolinks将会忽略那些容器里面的所有链接。当你使用document.ready的时候,会存在一个问题,那就是,这个事件只会在DOM完成加载的时候被触发,但是不会在Turbolinks更改了页面后被触发。一个快捷的修复方法是,document.ready和page:change事件:

$(function() {
initPage();
}); $(window).bind('page:change', function() {
initPage();
})

代码将会在页面被修改或者文档加载完毕时被执行。

注意:Turbolinks是用 CoffeeScript编写的,所以需要coffeescript-rails 的gem,来编译成javascript. 请确保这个gem已经添加到你的应用中。如果你不希望在你的应用中使用CoffeeScript,你可以手工的下载和编译turbolinks.js.conffee到Javascript。请参考CoffeeScript 文档,了解如何安装CoffeeScript和如何通过coffee -cturbolinks.js.coffee编译为turbolinks.js。

结论

Hacker News的一位用户 JuDue问了一个有趣的问题:

跟PJAX的比较怎么样?例如,Turbolinks是否已经足够灵活?

这个要看情况。Turbolinks明显的优化了客户端的页面加载性能。问题是,服务器端仍然需要渲染整个页面。如果在你的应用中,这个是瓶颈,那么Turbolinks将不会是最佳选择。PJAX在另一方面,可以通过只渲染页面的某些元素,来很好的解决这个问题,但是代价是,给开发过程带来更多的额外工作。

对于灵活性,这完全取决与你的需求。如果你只有很少的链接不需要Turbolinks处理的话,这完全没问题。如果你大部分的页面,只需要更新某些小的页面元素,并保持网络的小流量,那PJAX就是不二之选。

总的来说:Turbolinks可以明显地优化页面加载,如果你的页面使用Javascript和CSS样式。PJAX则更多的考虑服务器端的性能。