Làm việc với tốc độ tải trang trong Blogspot

Bài này được mình viết bằng cả quá trình dài tìm hiểu, thử nghiệm mới đưa ra được các phương pháp tối ưu nhất làm tăng tốc độ tải trang và cần khắc phục ở những điểm nào gây ảnh hưởng đến tốc độ tải trang trong Blogspot. Mình xin nhấn mạnh chỉ trong Blogspot thôi còn các mã nguồn khác mình không đề cập đến.

Vì đây là bài tổng hợp cho nên dài và có khi rất dài và có thể được cập nhật nếu mình phát hiện được phương pháp nào hay hơn do đó các bạn quan tâm có thể đọc tham khảo. Và còn vấn đề nữa vì những phương pháp này mình đả áp dụng thí nghiệm nên độ chính xác cao.

Trước hết bạn cần lưu ý ở những điểm sau đây:

+ Vấn đề bạn không nên quan tâm nhiều:

1. Sử dụng Google Pagespeed hay các trang web tương tự làm thước đo chính mà nên sử dụng tham khảo vì Pagespeed hay các trang web khác sử dụng thuận toán chung khi quét trang web nếu thấy vấn đề gì nó sẽ đưa vào cảnh báo mà không quan tâm đến thời gian tải trang.
2. Chặn js và css mặc định của Blog vì cho dù bạn chặn cũng không làm giảm thời gian tải trang đôi khi gây lỗi cho widget nếu bạn không làm đúng cách.

+ Vấn đề bạn cần quan tâm:

1. Kích thước hay còn gọi dung lượng của một trang khi tải
2. Quy tắc khi tải trang web phần nào được tải trước, phần nào được tải sau.
3. Tải feeds

Bây giờ mình sẽ đi vào phần trọng tâm của những vấn đề bạn cần quan tâm nó sẽ quyết định tốc độ tải trang

1. Kích thước một trang khi tải

Bây giờ mình sẽ lấy ví dụ minh họa kích thước của trang bằng quãng đường và thời gian chạy đến đích là thời gian tải xong trang. Như vậy quãng đường càng ngắn thì thời gian đến đích sẽ nhanh hơn. Và bây giờ chúng ta sẽ tìm hiểu những mục nào làm tăng kích thước trang bao gồm:

+ CSS
+ HTML
+ Ảnh
+ Script

Trong đó thì ảnh sẽ nặng nhất do đó chúng ta cần xử lý đến mức tối ưu nhất. Để có ảnh hiển thị thì trong bài viết chúng ta cần tải ảnh lên sử dụng host Blogger lưu trữ. Vấn đề bạn cần xử lý ảnh trước khi tải lên bằng 2 vấn đề sau:

+ Xác định độ rộng tối đa của vùng chứa ảnh, mình lấy ví dụ phần main-wrapper có độ rộng tối đa là 860px thì bạn cần thiết lập độ rộng của ảnh cũng tối đa là 860px, chẳng hạn tệp ảnh đó có độ rộng 2000px thì dung lượng của nó sẽ rất nặng tuy nhiên nếu bạn chỉnh lại độ rộng xuống còn 860px thì dung lượng ảnh sẽ giảm đi rất nhiều.

+ Nén ảnh trước khi tải lên bằng cách sử dụng các trang nén ảnh online trên mạng mục đích nén ảnh lại giảm dung lượng.

Sau khi bạn tải ảnh đó lên bài viết thì trong Blogger cho phép bạn điều chỉnh kích thước trong bài viết như sau:

Nhỏ: s200
Trung bình: s320
Lớn: s400
Rất lớn: s640
Kích thước band đầu: s1600

Như vậy nếu bạn thiết lập ảnh có kích thước ban đầu s1600 tương đương với kích thước chính của tệp ảnh khi bạn tải lên. Mình khuyến khích các bạn chỉ để kích thước trung bình s320 là đủ, tuy nhiên khi hiển thị trong bài viết ảnh sẽ nhỏ và mờ do đó bạn cần thay đổi bằng cách sử dụng js replace kích thước về ảnh gốc cho độ nét cao nhất

<head>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
</head>
<body>
...
<b:if cond='data:view.isSingleItem'>
  <script>//<![CDATA[
    $(document).ready(function() {
      $('.post-body .separator a,.post-body .tr-caption-container a').attr('href', function(o, n) {
        return n.replace('s200', 's1600').replace('s320', 's1600').replace('s400', 's1600').replace('s640', 's1600')
      })
      $('.post-body .separator img,.post-body .tr-caption-container img').attr('src', function(o, n) {
        return n.replace('s200', 's1600').replace('s320', 's1600').replace('s400', 's1600').replace('s640', 's1600')
      })
  //]]></script>
</b:if>
</body>

Chỗ này bạn cần để ý tải ảnh và thay đổi kích thước nó khác nhau vì khi tải trang sẽ chỉ tải ảnh có kích thước s320 còn khi tải xong ảnh thì js sẽ xử lý ảnh về kích thước gốc s1600 do đó tải ảnh và hiển thị ảnh hoàn toàn khác nhau tóm lại tải ảnh xong rồi mới xử lý ảnh.

Một vấn đề nữa về kích thước ảnh bạn cần quan tâm đó là ảnh đầu tiên của bài viết được lấy ra làm ảnh hiển thị bên ngoài trang index của widget Blog1, PopularPosts, FeaturePosts. Do bạn đã thiết lập ảnh kích thước s320 thì ảnh mặc định đầu tiên khi tải và hiển thị ngoài trang index cũng chỉ có kích thước là s320, nếu bạn thấy mờ do kích thước nhỏ bạn cũng có thể sử dụng js replace ảnh  của widget Blog1 còn widget PopularPosts để kích thước s320 là hợp lý

<head>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
</head>
<body>
...
<b:if cond='data:view.isMultipleItems'>
  <script>//<![CDATA[
    $(document).ready(function() {
      $('.post img').attr('href', function(o, n) {
        return n.replace('s200', 's1600').replace('s320', 's1600').replace('s400', 's1600').replace('s640', 's1600')
      })
  //]]></script>
</b:if>
</body>

Ngoài ra trong Blogger cung cấp sẵn hàm resize ảnh mặc định rất tốt đó là hiển thị ảnh theo kích thước màn hình nếu như trên máy tính bạn không thấy tác dụng nhiều nhưng ngược lại với điện thoại thì tốc độ tải trang sẽ tăng rất tốt do vậy bạn nên áp dụng như sau:

// widget Blog1 version 1

<b:if cond='data:post.firstImageUrl'>
  <div class='post-thumb'>
    <a expr:href='data:post.url' expr:title='data:post.title'>
    <img expr:alt='data:post.title' expr:src='data:post.firstImageUrl' expr:srcset='sourceSet(data:post.firstImageUrl, [200,320,400,640,1600], &quot;16:9&quot;)'/>
    </a>
  </div>
  <b:else/>
  <div class='post-thumb'>
    <a expr:href='data:post.url' expr:title='data:post.title'>
    <img expr:alt='data:post.title' expr:srcset='sourceSet(&quot;https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s1600/safe_image.png&quot;, [200,320,400,640,1600], &quot;16:9&quot;)' src='https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s1600/safe_image.png'/>
    </a>
  </div>
</b:if>

// widget Blog1 version 2

<b:if cond='data:post.featuredImage'>
  <div class='post-thumb'>
    <a expr:href='data:post.url' expr:title='data:post.title'>
    <img expr:alt='data:post.title' expr:src='data:post.featuredImage' expr:srcset='sourceSet(data:post.featuredImage, [200,320,400,640,1600], &quot;16:9&quot;)' sizes='(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)'/>
    </a>
  </div>
  <b:else/>
  <div class='post-thumb'>
    <img expr:alt='data:post.title' expr:srcset='sourceSet(&quot;https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s1600/safe_image.png&quot;, [200,320,400,640,1600], &quot;16:9&quot;)' sizes='(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)' src='https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s320/safe_image.png'/>
  </div>
</b:if>

Áp dụng trong widget PopularPosts version 1 thay ảnh như sau:

<b:if cond='data:post.featuredImage.isResizable or data:post.thumbnail'>
  <div class='item-thumbnail'>
    <a expr:href='data:post.href' expr:title='data:post.title'>
    <img expr:alt='data:post.title' expr:src='data:post.featuredImage' expr:srcset='sourceSet(data:post.featuredImage, [200,320,400,640,1600], &quot;16:9&quot;)' sizes='(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)'/>
    </a>
  </div>
  <b:else/>
  <div class='item-thumbnail'>
    <a expr:href='data:post.href' expr:title='data:post.title'>
    <img expr:alt='data:post.title' expr:srcset='sourceSet(&quot;https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s1600/safe_image.png&quot;, [200,320,400,640,1600], &quot;16:9&quot;)' sizes='(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)' src='https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s320/safe_image.png'/>
    </a>
  </div>
</b:if>

Tiếp theo chúng ta sẽ xử lý ảnh hiển thị trong feeds

Khi xây dựng các widget Recent Posts, Random Posts chúng ta phải sử dụng feeds để lấy dữ liệu trong đó có ảnh thế thì ảnh mặc định trong feeds luôn được tối ưu về kích thước nhỏ nhất s72-c có rộng và cao bằng 72px tức là ảnh vuông và khi viết script lấy ảnh như sau:

<body>
<script>//<![CDATA[
function getPosts(e) {
  for (var t = 0; t < e.feed.entry.length; t++) {
    var thumb = e.feed.entry[t].media$thumbnail.url,
          thumbsrc = "<img src='+ thumb +'/>";
  }
}
//]]></script>
</body>

sẽ cho ra ảnh mặc định s72-c

Thay vào đó chúng ta sẽ xây dựng đoạn script lấy ảnh như sau:

<body>
<script>//<![CDATA[
function getPosts(e) {
  for (var t = 0; t < e.feed.entry.length; t++) {
    var thumb  =  e.feed.entry[t].media$thumbnail.url,
          w200   =  thumb.replace("s72-c", "w200-h112-p-k-no-nu"),
          w320   =  thumb.replace("s72-c", "w320-h180-p-k-no-nu"),
          w400   =  thumb.replace("s72-c", "w400-h225-p-k-no-nu"),
          w640   =  thumb.url.replace("s72-c", "w640-h360-p-k-no-nu"),
          w1600 = thumb.replace("s72-c", "w1600-h900-p-k-no-nu"),
          thumbsrc = "<img src=' + w320 + '  sizes="(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)" srcset="' + w200 + " 200w, " + w320 + " 312w, " + w400 + " 400w, " + w640 + " 640w, " + w1600 + ' 1600w"/>";
  }
}
//]]></script>
</body>

Như vậy khi tải trang ảnh trong widget sẽ hiển thị như ví dụ sau:

<img src="https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/s320/2018-07-06_11-55-35.jpg" sizes="(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)" srcset="https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/w200-h112-p-k-no-nu/2018-07-06_11-55-35.jpg 200w, https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/w320-h180-p-k-no-nu/2018-07-06_11-55-35.jpg 312w, https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/w400-h225-p-k-no-nu/2018-07-06_11-55-35.jpg 400w, https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/w640-h360-p-k-no-nu/2018-07-06_11-55-35.jpg 640w, https://2.bp.blogspot.com/-SKLavBNCuBU/Wz8PpceEJ2I/AAAAAAAAL98/tMic035ntDonkgMsZB0SGaLg_N-chNfeQCLcBGAs/w1600-h900-p-k-no-nu/2018-07-06_11-55-35.jpg 1600w">

Ngoài Ảnh ra thì các mục còn lại css, html, script có dung lượng không đáng kể gộp tất cả lại cũng không bằng kích thước của một tệp ảnh do đó bạn cũng đừng quan trọng quá về kích thước của những tệp này.

2. Quy tắc khi tải trang web

Nguyên tắc tải trang web sẽ theo thứ tự từ trên xuống giống như nước chảy từ trên cao xuống chỗ thấp và trong cấu trúc tải trang sẽ tải theo trình tự css - html (bao gồm ảnh) - script, chúng ta đi vào phân tích một chút về trình tự này

CSS được tải trước để khi HTML tải xong sẽ hiển thị và cuối cùng script được tải để xứ lý như vậy nếu script được tải trước HTML thì HTML phải đợi script tải xong mới được tải mà chúng ta cần hiển thị trước do đó script bao giờ cũng phải đặt dưới cùng ngay trên thẻ đóng </body>.

Chúng ta lại phân tích tiếp về script trong đó lại bao gồm các đoạn js hay javascript hiển thị các nội dung khác nhau và tại các trang khác nhau. Trở lại với ví dụ ban đầu cùng một quãng đường nhưng tại sao anh A lại chạy tới trước anh B là do anh A có lực hơn và biết xử lý kỹ thuật trong thời gian chạy tốt hơn anh B do đó anh A sẽ đến trước anh B.

Áp dụng vào các đoạn script A hiển thị nội dung A, đoạn script B hiển thị nội dung B mà nguyên tắc tải trang và hiển thị từ trên xuống thì nếu A nằm trước B thì đoạn script A phải được nằm trên đoạn script B để được tải và hiển thị trước.

Tất nhiên chúng ta cần đặt điều kiện tải script cho các trang khác nhau bằng thẻ điều kiện trong Blogspot ví dụ đoạn script đó chỉ chạy tại trang chủ thì sử dụng điều kiện

<body>
<b:if cond='data:view.isHomepage'>
  <script>//<![CDATA[
    // đoạn script A hoặc B
  //]]></script>
</b:if>
</body>

Tiếp theo chúng ta sẽ sử dụng phương thức document ready và window onload để tải script áp dụng khi css và html tải xong mới tải script. Nếu trong jquery sử dụng $(document).ready(function() thì trong javascript thuần sử dụng window.onload = function() và trong jquery cũng có hàm tương đương là $(window).on('load', function(). Sự giống nhau và khác biệt chính của 2 phương thức này như sau:

Giống nhau: Đều đợi html tải trước
Khác nhau: document ready sẽ tải script ngay khi html mới tải một phần chứ chưa tải xong còn window onload phải đợi html tải xong mới tải script.

Như vậy trong hai phương thức trên thì sử dụng phương thức nào tốt hơn? Tùy vào từng trường hợp mà sử dụng phương thức nào nếu viết script sử dụng jquery thì sử dụng document ready tỏ ra hiệu quả hơn còn nếu sử dụng javascript thì áp dụng window onload.

Tuy nhiên như đề cập ở trên đoạn script A đặt trên đoạn script B mà cả 2 đều sử dụng phương thức window onload do đó sẽ gây ra tình trang đơ hay trang bị lag do cùng tải một lượt. Do đó đoạn script A sử dụng phương thức document ready trong khi đoạn script B được xử lý sau cùng với window onload.

Cuối cùng không thể không đề cập đến iframe và link js của nhận xét trong bài viết, vấn đề này mình đã có viết hướng dẫn trong Blog các bạn tham khảo link https://vietblogdao.blogspot.com/2018/09/huong-da-tai-comment-form-sau-khi-tai-trang-hoac-tao-button-click.html mục đích chính là khi truy cập bài viết để đọc chứ ít khi vào để nhận xét do đó chúng ta thiết lập cho khung nhận xét và nội dung nhận xét được tải sau khi bài viết tải xong hoặc chúng ta cũng có thể thiết lập sử dụng button click load khung nhận xét cũng được do đó tốc độ tải trang cũng nhanh hơn.

3. Tải feeds

Vấn đề này được nhiều người quan tâm vì nó làm ảnh hưởng rất nhiều đến tốc độ tải trang, như đã đề cập phần trên khi xây dựng các widget Recent Posts, Random Posts, Recent Comments bắt buộc phải sử dụng feeds mà feeds lại được chia làm 2 loại:

Loại tóm tắt: /feeds/posts/summary
Loại đầy đủ: /feeds/posts/default

Sự khác biệt của 2 loại feeds này nếu như summary chỉ lấy duy nhất một ảnh của mỗi bài viết và đoạn tóm tắt thì default sẽ tải đầy đủ tất cả ảnh và nội dung bài viết do đó tải feeds bằng tóm tắt nhanh và hiệu quả hơn so với feeds đầy đủ vì khi xây dựng chúng ta cũng chỉ cần lấy ảnh đầu tiên và đoạn tóm tắt chứ đâu lấy hết nội dung.

Thứ hai khi xây dựng widget Random Posts bài viết ngẫu nhiên thường phải tải feeds với tối đa số bài viết mà trong khi chỉ lấy số bài viết cụ thể, lấy ví dụ:

/feeds/posts/summary?alt=json-in-script&max-results=5

sẽ tải 5 bài viết so với

/feeds/posts/summary?alt=json-in-script&max-results=150

phải tải max là 150 bài viết do đó thời gian tải feeds này lâu hơn rất nhiều trong khi lại lọc lấy 5 bài viết hiển thị ngẫu nhiên.

Gải pháp ở đây tối ưu hơn đó là chia mỗi bài viết cho 1 feeds sử dụng start-index và max-results=1 &callback=randomposts chẳng hạn

/feeds/posts/summary?alt=json-in-script&start-index=10&max-results=1&callback=randomposts
/feeds/posts/summary?alt=json-in-script&start-index=3&max-results=1&callback=randomposts
/feeds/posts/summary?alt=json-in-script&start-index=40&max-results=1&callback=randomposts
/feeds/posts/summary?alt=json-in-script&start-index=101&max-results=1&callback=randomposts
/feeds/posts/summary?alt=json-in-script&start-index=512&max-results=1&callback=randomposts

Như vậy với mỗi feeds được tải sẽ chỉ tải 1 bài và được lấy bài viết ngẫu nhiên bằng start-index. Rõ ràng cùng 1 thời gian nếu tải 5 cái feeds chỉ có 1 bài sẽ nhanh hơn 1 cái feeds 150 bài.

Cuối cùng là sử dụng phương thức get script hay ajax sẽ hiệu quả hơn so với đặt script trực tiếp vì nếu sử dụng các phương thức trên chúng ta sẽ kết hợp với phương thức document ready và window onload tải feeds tải sau khi html được tải. Lấy ví dụ minh họa

+ Sử dụng phương thức get script

<body>
<script>//<![CDATA[
$(window).on('load', function() {
  $.getScript('/feeds/posts/summary?alt=json-in-script&max-results=5&callback=recentposts')
})
//]]></script>
</body>

+ Sử dụng phương thức ajax

<body>
<script>//<![CDATA[
$(window).on('load', function() {
  $.ajax({
    type: 'GET',
    url: '/feeds/posts/summary',
    data: {
      'max-results': 5,
      'alt': 'json'
    },
    dataType: 'jsonp',
    jsonp: 'callback',
    jsonpCallback: 'recentposts',
    success: function() {
      $('.recent-posts').removeClass('spinner').removeClass('load')
    }
  })
})
//]]></script>
</body>

Trên đây là những phương pháp làm tăng tốc độ tải trang, trong quá trình viết bài có thể sai xót gây ra nhầm lẫn cho các bạn nếu không hiểu. Mình sẽ cập nhật lại khi có phương pháp nào mới hay hơn. Chấm hết bài!!!
Bài đăng mới hơn Bài đăng cũ hơn
Bài viết này có hữu ích không?