रेल्स की फ्रैगमेंट कैशिंग तब अधिक गति बढ़ाती है जब पेज का बड़ा हिस्सा कैश्ड होता है। यह डायनामिक या यूज़र-स्पेसिफिक कंटेंट वाले पेजों के लिए अधिक कठिन है। एक समाधान "जावास्क्रिप्ट स्प्रिंकल्स" का उपयोग करना है, जो हैगेलस्लैग की तरह है, लेकिन चॉकलेट के बिना और पेज का बाकी हिस्सा सीधे कैश से सर्व होने के बाद यूज़र-स्पेसिफिक कंटेंट लोड करने के लिए अतिरिक्त अनुरोधों के साथ।
फ्रैगमेंट कैशिंग
फ्रैगमेंट कैशिंग जैसी तकनीकों का उपयोग रेल्स एप्लिकेशन्स में रेंडर्ड पेज के फ्रैगमेंट्स को कैश करके प्रतिक्रियाओं को गति देने के लिए किया जाता है। स्मार्ट कैश कीज़ का उपयोग करके, जब उनके कंटेंट बदलते हैं क्योंकि व्यू में दिखाया गया डेटा अपडेट होता है तो फ्रैगमेंट्स स्वचालित रूप से अमान्य हो जाते हैं।
कैशिंग व्यू फ्रैगमेंट्स एक छोटे कैश से बड़ा स्पीड बूस्ट प्रदान करता है जब कैश्ड फ्रैगमेंट्स अधिक बार उपयोग किए जाते हैं। जब पेज का कंटेंट वर्तमान में साइन-इन यूज़र पर निर्भर करता है, उदाहरण के लिए, पेज के फ्रैगमेंट्स को कैश करना अधिक कठिन हो जाता है।
अनरीड रिस्पॉन्सेस
उदाहरण के तौर पर, आइए एक रेल्स-आधारित ब्लॉग लें। इस ब्लॉग पर, प्रत्येक आर्टिकल में कई रिस्पॉन्सेस हो सकते हैं। एक प्रमाणीकरण प्रणाली जोड़ी गई थी ताकि यूज़र्स साइन इन कर सकें और अपने अकाउंट्स के साथ रिस्पॉन्सेस पोस्ट कर सकें। प्रत्येक आर्टिकल पेज पर, हम रिस्पॉन्सेस सूचीबद्ध करते हैं। हमारे यूज़र्स के लिए इसे आसान बनाने के लिए, हम नए रिस्पॉन्सेस को एक आइकन और एक अलग बैकग्राउंड कलर के साथ चिह्नित करते हैं।
अगर हम प्रत्येक आर्टिकल को cache ब्लॉक में लपेटते हैं, तो हम गलत रिस्पॉन्सेस को अनरीड के रूप में चिह्नित करने का जोखिम उठाते हैं। जब एक यूज़र इंडेक्स पेज का अनुरोध करता है, तो रिस्पॉन्स कैश्ड होता है। जब दूसरा यूज़र बाद में उसी पेज का अनुरोध करता है, तो उन्हें कैश्ड फ्रैगमेंट प्राप्त होगा, जिसमें पहले यूज़र के अनरीड रिस्पॉन्सेस होंगे।
# app/views/articles/show.html.erb
<%= cache(@article) do %>
<h1><%= @article.title %></h1>
<%= simple_format(@article.content) %>
<section id="responses">
<h2>Responses</h2>
<% @article.responses.each do |response| %>
<div class="<%= response.read_by?(@current_user) ? 'read' : 'unread' %>">
<%= time_tag(response.created_at) %>
<strong><%= response.name %></strong>: <%= response.content %>
</div>
<% end %>
</section>
<% end %>
इसे हल करने का एक तरीका [@article, @current_user] का उपयोग करके वर्तमान में साइन-इन यूज़र को कैश की में जोड़ना है, बजाय केवल @article के cache हेल्पर मेथड को पास किए गए आर्ग्युमेंट के रूप में।
# app/views/articles/show.html.erb
<%= cache([@article, @current_user]) do %>
<h1><%= @article.title %></h1>
# ...
<% end %>
यह सुनिश्चित करता है कि प्रत्येक यूज़र अपने अनरीड रिस्पॉन्सेस देखे, लेकिन कैशिंग फ्रैगमेंट्स से अधिकांश स्पीडअप को नकार देता है, क्योंकि आर्टिकल फ्रैगमेंट्स अब प्रत्येक यूज़र के लिए अलग से कैश्ड हैं।
जावास्क्रिप्ट स्प्रिंकल्स
चूंकि पेज का अधिकांश हिस्सा सभी यूज़र्स के लिए समान है, हम प्रत्येक विज़िटर के लिए कैश्ड आर्टिकल फ्रैगमेंट का पुन: उपयोग करना चाहेंगे। ऐसा करने के लिए, हम कैश से आर्टिकल लोड कर सकते हैं और पेज लोड होने के बाद जावास्क्रिप्ट अनुरोध के माध्यम से यूज़र-स्पेसिफिक कंटेंट लाने के लिए एक अतिरिक्त अनुरोध जोड़ सकते हैं। इस कार्यक्षमता के लिए जावास्क्रिप्ट के स्प्रिंकल का उपयोग करने के कुछ फायदे हैं:
- पेज को एक बार कैश किया जा सकता है और अनधिकृत मेहमानों के साथ-साथ अन्य यूज़र्स के लिए पुन: उपयोग किया जा सकता है बिना हर यूज़र के लिए अलग से फ्रैगमेंट्स कैश किए।
- सबसे महत्वपूर्ण कंटेंट सबसे तेज प्रतिक्रिया समय के लिए पहले लोड होता है और सेकेंडरी फीचर्स, जैसे अनरीड काउंट, बाद में लोड होते हैं।
- चूंकि अतिरिक्त अनुरोध जावास्क्रिप्ट के माध्यम से किया जाता है, पूरा पेज CDN पर एज-कैश्ड हो सकता है ताकि प्रदर्शन को और बेहतर बनाया जा सके।
सफाई
हम पहले अपने पेजों से डायनामिक कंटेंट को हटाकर उन्हें कैश करना आसान बनाएंगे। हम cache ब्लॉक में @current_user को फिर से हटा देंगे, इसलिए वे अब प्रत्येक यूज़र के लिए कैश्ड नहीं हैं। फिर, हम कंट्रोलर से अनरीड काउंट्स को खोजने वाली क्वेरी को हटा देंगे, और व्यू से CSS क्लास नामों को हटा देंगे।
# app/views/articles/show.html.erb
<%= cache(@article) do %>
<h1><%= @article.title %></h1>
<%= simple_format(@article.content) %>
<section id="responses">
<h2>Responses</h2>
<% @article.responses.each do |response| %>
<div data-response-id="<%= response.id %>">
<%= time_tag(response.updated_at) %>
<strong><%= response.name %></strong>: <%= response.content %>
</div>
<% end %>
</section>
<% end %>
हमारे पास एक जेनेरिक पेज बचा है जिसे कैश करना आसान है लेकिन इसमें हमारा अनरीड रिस्पॉन्सेस फीचर नहीं है। आइए इसे वापस जोड़ें।
एंडपॉइंट
हम पहले यूज़र के लिए अनरीड रिस्पॉन्सेस खोजने के लिए एक एंडपॉइंट बनाएंगे। हम पेज रेंडर होने के बाद उसकी वर्तमान स्थिति को बदलना चाहेंगे, इसलिए हम इससे JSON का अनुरोध करेंगे।
# app/controllers/unread_responses_controller.rb
class UnreadResponsesController < ApplicationController
def index
@article = Article.find(params[:article_id])
@responses = @article.unread_responses_for(@current_user)
end
end
# app/views/unread_responses/index.json.jbuilder
json.array! @responses do |response|
json.extract! response, :id
end
# config/routes.rb
Rails.application.routes.draw do
resources :articles do
resources :responses
resources :unread_responses
end
end
हमारा एंडपॉइंट अनरीड रिस्पॉन्स आईडीज़ की एक सूची तैयार करेगा।
# GET /articles/1/unread_responses.json
[{"id":1},{"id":2},{"id":3}]
टिप: जब एक डायनामिक कंपोनेंट लोड कर रहे हों जिसे सर्वर-साइड प्री-रेंडर किया जा सकता है, तो आमतौर पर सर्वर साइड पर HTML रेंडरिंग करना तेज़ होता है, फिर जावास्क्रिप्ट के माध्यम से HTML को सीधे अपने पेज में इंजेक्ट करें।
अनरीड रिस्पॉन्सेस दिखाना
जावास्क्रिप्ट कोड में अनरीड रिस्पॉन्सेस एंडपॉइंट के URL को हार्डकोड करने के बजाय, हम इसे व्यू में डेटा एट्रिब्यूट में जोड़ देंगे, ताकि हम बाद में इसका संदर्भ ले सकें।
# app/views/articles/show.html.erb
<section id="responses" data-url="<%= article_unread_responses_path(@article, json: true) %>">
# ...
</section>
पेज लोडिंग पूरा होने के बाद, हम अपने नए एंडपॉइंट से अनरीड रिस्पॉन्स आईडीज़ का अनुरोध करेंगे। हम तब उस सूची से डेटा का उपयोग प्रत्येक आर्टिकल को अनरीड के रूप में चिह्नित करने के लिए CSS क्लास जोड़कर करेंगे।
// app/assets/javascripts/application.js
document.addEventListener("turbolinks:load", function () {
responses = document.getElementById("responses");
if (!responses.dataset.loaded) {
Rails.ajax({
url: responses.dataset.url,
type: "GET",
success: function (data) {
responses.dataset.loaded = true;
data.forEach(function (response) {
element = document.querySelector(
"[data-response-id='" + response.id + "']"
);
element.classList.add("unread");
});
},
});
}
});
क्योंकि हमारा रेल्स एप्लिकेशन Turbolinks का उपयोग करता है, हम पेज लोड होने की प्रतीक्षा करने के लिए turbolinks:load इवेंट को सुनेंगे। जब वह इवेंट फायर होता है, तो हम इसकी आईडी का उपयोग करके रिस्पॉन्सेस बॉक्स ढूंढेंगे।
हम तब जांचेंगे कि क्या रिस्पॉन्सेस एलिमेंट में loaded डेटा एट्रिब्यूट है। हम इस एट्रिब्यूट को बाद में अनरीड रिस्पॉन्सेस अपडेट करने के बाद सेट करेंगे, ताकि पेज ब्राउज़र के बैक बटन का उपयोग करके रीलोड होने पर हम कोई अतिरिक्त अनुरोध न करें।
पहले लोड पर, loaded एट्रिब्यूट अभी तक सेट नहीं है, इसलिए हम अपने एंडपॉइंट पर अनुरोध करना जारी रखेंगे। सफलता पर, हम वापस आए परिणाम में प्रत्येक आर्टिकल पर लूप करेंगे, इसकी आईडी द्वारा रिस्पॉन्स के एलिमेंट को ढूंढेंगे, और इसमें हमारी "unread" CSS क्लास जोड़ेंगे।
स्प्रिंकल्स!
पुन: प्रयोज्य कंटेंट को फ्रैगमेंट कैशिंग करना और अपने पेजों पर जावास्क्रिप्ट स्प्रिंकल करना ताकि यूज़र-स्पेसिफिक डायनामिक बिट्स बाद में जोड़े जा सकें, आपके ऐप के प्रारंभिक प्रतिक्रिया समय को तेज़ बना सकता है क्योंकि अधिकांश महत्वपूर्ण कंटेंट सीधे कैश से सर्व होता है। हालांकि अतिरिक्त अनुरोध करने और मुख्य कंटेंट लोड होने के बाद पेज को अपडेट करने में समय लगता है, डायनामिक कंटेंट को डेफर करने से आपका ऐप स्नैपियर महसूस होगा, भले ही पूरा अनुरोध कैश से सब कुछ सर्व करने से अधिक समय लेता हो, जिसमें यूज़र-स्पेसिफिक पार्ट्स शामिल हैं।
अधिक विस्तृत सेटअप के लिए, Stimulus को अवश्य देखें, एक जावास्क्रिप्ट लाइब्रेरी जो स्प्रिंकल्स पैटर्न को एक फ्रेमवर्क में लपेटती है जो आपके HTML व्यूज को आपके जावास्क्रिप्ट से जोड़ती है।
हमें उम्मीद है कि आपको रेल्स एप्लिकेशन्स में जावास्क्रिप्ट स्प्रिंकल्स का यह परिचय पसंद आया। यदि आपके पास इस लेख, ब्लॉग या किसी अन्य विषय के बारे में कोई टिप्पणी है जिसे आप कवर करना चाहेंगे, तो कृपया @AppSignal पर हमें एक लाइन लिखें।