Rails: 只在需要的時候加載需要的 JavaScript

jopen 11年前發布 | 19K 次閱讀 Rails Ruby開發

一年前我做了一個關于這個主題的演講。我第一次關注這個技術是因為 @dhh發布的他們在 37signals使用的一些觀點。我注意到他們 模板視圖里</span>如何使用JavaScript,動態生成JavaScript這是它的關注點,這引起了我的思考。

與之前我們在前端加載全部javascript相比,為什么我們不加載最少量的JavaScript然后在用戶界面需要的時候再加載額外的JavaScript代碼呢?

我把這稱為響應式的JavaScript,你聽說過pjax這個 術語,或者 unobtrusive JavaScript,等等。目的是后端的JavaScript按前端動作加載。不管是GET、POST、DELETE等待,只要請求是ajax,響應將會是JavaScript而不是JSON。

你使用的一些產品中的一些實例或許已經使用這個 概念了。BCX、GitHub、Airbnb都以不同方式使用了這個概念。這一概念的問題在于它不綁定任何的庫或框架,你必須使用目前的工具來它工作。慶幸,現在已經有了一個JavaScript庫可以幫助你開始。jQuery-UJS可以讓你添加 remote=”true” 到任何鏈接,這些鏈接會自動轉換成一個Ajax調用。

首先,一個例子

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

def show @post = Post.find params[:id].to_i respond_to do |format| format.js format.html end end

def create

#.. Create a post
respond_to do |format|
  format.js
  format.html
end

end end</pre>

<!-- app/views/index.html.erb -->
<ul class="posts">
  <%= @posts.each do |post| %>
    <%= render_link_to_post(post) %>
  <% end %>
</ul>
# app/views/create.js.erb
(function() {
  var $post = $("<%= j render_link_to_post(@post) %>")
  $post.hide().prependTo($("ul.posts")).fadeIn()
})()
# app/views/show.js.erb
(function() {
  var $post = $("<%= j render("overview", post: @post) %>")
  $post.dialog("open")
})()
<!-- app/views/show.html.erb -->
<div class="title">
  <%= @post.title %>
</div>
<div class="body">
  <%= @post.body %>
</div>
#helper.rb
def render_link_to_post(post)
  link_to post.title, post_path(post), remote: true
end

在這個例子中,當有人點擊鏈接,它將會調用/posts/:id。如果請求是AJAX,它將調用show.js.erb,執行模板里的代碼。如果不是的話,它將調用show.html.erb。還有一個叫created.js.erb模板,當你通過Ajax表單創建一個資源時將被調用。表單被清理的盡可能簡單。

URL幫你定位到bug

假設你點擊鏈接時有一個bug,通過使用這種技術,你可以通過查看URL追溯起源。
舉例:posts/:id與與位于app/views/posts/show.js.erb的JS模板相關聯。
正如你在處理HTML視圖時所期望的一樣。

web頁面有生命期

回顧一下上面的例子。當你用Ajax表單發布一條post,按預設列表將生成一個與該post對應的鏈接。看一下請求的方法:它和你調用/posts時相同,這不是一種偶然。當你使用這種方法時會試圖避免代碼重復,ajax除了不最終生成頁面外與正常請求使用相同的組件。

這意味著,當你發布一個新post后,如果你刷新頁面,將會顯示相同的文章列表,因為它們使用了相同的機制。

復用相同的視圖邏輯

這是一個以前的擴展。既然在服務器端已經生成了HTML,你可能會在視圖里看到很多重復代碼,使用助手類或修飾器來簡化代碼將不會是件難事。

因為所有映射都來自從同一個地方,HTML的修改也可以在同一個地方完成。比如,如果我想要將列表中的鏈接替換成一個更具描述性的,我可以修改render_link_to_post(一個壞的函數名,原諒我)的實施細則以適應變化。

JavaScript在動作間的傳遞 & 頁面加載優化

現在,你的JavaScript在2個不同的地方加載

  1. 由標簽鏈接加載JavaScript。在頁面加載時加載,運行時不能定制,JavaScript可以被預編譯;
  2. 作為用戶頁面動作的響應加載。
  3. </ol>

    對服務內容能更好的控制是這種方式的優點。如果你感覺解析代碼較多時慢,你可以一些請求時的負載抽取到標簽鏈接中加載。

    當需要時加載需要的

    由于網頁在服務器端的渲染,所以響應最小化時你有很多可選的庫,也許你可以試試jQuery、Zepto或其他什么的,但記住:JavaScript幾乎從來(我不知道是不是每個都是)不在加載時渲染頁面,加載完后才開始。

    看看上面的例子。create.js.erb上有個問題,我可以用很好的功能和其他好東西來包裝它,但如果人們從不發布post這有什么意義呢。

    這需要你維持一個平衡。當有有些東西大量使用是(每用戶每頁使用超過一次),像你其他庫一樣用標簽來加載它吧,其他的當HTML動作觸發時再加載吧。

    可重復的動作(調試目的)

    你是否遇到過這種情況,當你調試應用的時候3~4個不同的動作都提示你的javascript代碼里有bug?因為響應是獨立的JavaScript代碼,你只能將響應粘貼到控制臺一步步捕捉異常。

    我做了什么呢,我拿掉了擋在我和我正在使用變量間的障礙,這樣,在控制臺了我可以將bug縮小到變量層面。

    清晰

    客戶端的JavaScript通常與通知或事件搭配使用,觸發這些事件、收到服務器更新,這一切瞬間就緒。通常瞬間見效的事通常難以追蹤。

    當響應是JavaScript代碼時結果就很容易理解了。看看上面的例子,我詳細你能明白這兩個Ajax響應的預期行為。

    就是這樣

    這是我的選擇,你可也可以有自己的選擇。我希望你喜歡這篇文章且有了自己嘗試一下的沖動。 

    如果你實現了,在推ter給我留言告訴我它是如何運行的!

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!