Phát triển trang web thời gian thực dễ dàng với Meteor

Thực hiện nhanh chóng các ứng dụng hướng dữ liệu đáp ứng gần như ngay lập tức với sự tương tác của người dùng

Vì sự phổ biến của web, thậm chí chỉ cần một sự chậm trễ nhỏ trong việc cung cấp dữ liệu cũng có thể gây khó chịu cho người dùng. Họ muốn dữ liệu được cập nhật ngay lập tức. Thật không may, công nghệ web đã không thể bắt kịp nhu cầu truy cập theo thời gian thực. Trong khi việc truy xuất dữ liệu nhanh chóng được chuẩn hóa vào một vài lớp của Ánh xạ Đối tượng - Quan hệ (Object-Relational Mapping - ORM), thì giao tiếp thời gian thực lại không có giải pháp nào như vậy. Bài viết này bàn về Meteor, một khung cộng tác (framework) JavaScript mới thú vị, nhằm mục đích giải quyết vấn đề này.

David Berube, Chủ sở hữu, Berube Consulting

Ảnh của David BerubeDavid Berube là một chuyên gia tư vấn, diễn giả và là tác giả của các cuốn sách Practical Rails Plugins, Practical Reporting with Ruby and Rails, và Practical Ruby Gems. Ông cũng từng viết bài cho một số tạp chí, trong đó có cả Dr. Dobb's JournalLinux Pro Magazine. Ông phát triển phần mềm và tư vấn hiệu năng cho nhiều khách hàng và các lĩnh vực công nghiệp.



29 10 2013

Meteor là gì?

Meteor là một khung cộng tác JavaScript mới với mục đích tự động và đơn giản hóa việc phát triển một ứng dụng web hoạt động thời gian thực. Nó xử lý giao tiếp thời gian thực bằng một giao thức gọi là Giao thức Dữ liệu Phân tán (Distributed Data Protocol - DDP), nó được hỗ trợ trên các trình duyệt mới hơn sử dụng WebSockets và trên các trình duyệt cũ hơn sử dụng AJAX Long-Polling. Trong cả hai trường hợp, giao tiếp giữa trình duyệt và máy chủ là trong suốt.

Giao thức DDP được thiết kế để làm việc với tập hợp các tài liệu JSON (JavaScript Serialized Object Notation - Ký pháp đối tượng JavaScript tuần tự), khiến nó dễ dàng tạo, cập nhật, xóa, truy vấn, và dĩ nhiên - xem các tài liệu JSON. Bởi DDP là một giao thức nguồn mở, bạn có thể hình dung ra việc kết nối nó tới bất kỳ máy khách hoặc nguồn dữ liệu nào bạn muốn. Nó có thể hoạt động ngay lập tức cùng với MongoDB.

Trong thực tế, Meteor cung cấp hai cơ sở dữ liệu MongoDB: một cơ sở dữ liệu đệm ở phía máy khách và một cơ sở dữ liệu MongoDB trên máy chủ. Khi người dùng tạo ra một thay đổi đến một vùng dữ liệu—Ví dụ như nhấn nút Lưu (Save)—mã JavaScript chạy trên trình duyệt cập nhật các mục trong cơ sở dữ liệu MongoDB nội tại tương ứng và tạo ra một yêu cầu DDP tới máy chủ. Đoạn mã ngay lập tức được xử lý như thể là đã thành công bởi vì nó không cần chờ đợi để máy chủ trả lời. Trong khi đó, máy chủ âm thầm cập nhật dữ liệu. Nếu thao tác ở phía máy chủ thất bại hoặc trả về một kết quả không mong muốn, mã JavaScript ở phía máy khách ngay lập tức được điều chỉnh lại dựa vào dữ liệu vừa được trả về từ máy chủ. Sự điều chỉnh này được gọi là bồi hoàn trễ - latency compensation và tạo thêm cảm nhận về tốc độ cho người dùng.

Mặc dù hệ thống khuôn mẫu của Meteor được thiết kế một cách rõ ràng để dễ dàng tạo ra sự giao tiếp theo thời gian thực. Trong hầu hết các khung cộng tác web, bạn có thể dễ dàng trộn lẫn HTML (Ngôn ngữ đánh dấu văn bản siêu liên kết - Hypertext Markup Language)—hoặc tương đương với HTML, ví dụ như HTML Abstraction Markup Language (Haml)—với mã nguồn. Điều này cho phép bạn dễ dàng chèn các giá trị động từ cơ sở dữ liệu vào các trang mà bạn gửi cho người sử dụng. Sau đó, bạn có trách nhiệm đặt một hệ thống tại chỗ để giám sát các sự thay đổi trên dữ liệu và cập nhật các đánh đấu của bạn. Tuy vậy, hệ thống khuôn mẫu trong Meteor được thiết kế để ghi lại dữ liệu nào được truy cập từ một khuôn mẫu và tự động thiết lập các lời gọi lại để thay đổi HTML khi mà dữ liệu bên dưới thay đổi, khiến cho các khuôn mẫu thời gian thực nhanh chóng và dễ dàng.


Ví dụ: Cuộc thi bình chọn liên kết phổ biến

Tính năng khuôn mẫu của Meteor có thể giúp bạn tạo ra một loạt các ứng dụng thời gian thực dễ dàng hơn nhiều. Ví dụ, giả sử bạn muốn tạo ra một trang web, nơi mà những người dùng có thể nhập vào các liên kết—đó là các URL—và bỏ phiếu bầu ủng hộ hay không ủng hộ nó, với các URL chiến thắng sẽ được hiển thị ở đầu danh sách. Với Meteor, bạn có thể dễ dàng viết một ứng dụng như vậy theo thời gian thực do đó những người dùng có thể thấy được 65 lượt bỏ phiếu của những người dùng khác giống như họ.


Cài đặt Meteor

Để cài đặt Meteor, gõ đoạn mã sau trong Terminal của Liệt kê 1 Linux® hoặc Mac OS® X . Meteor không hỗ trợ Microsoft® Windows®.

Liệt kê 1. Cài đặt Meteor
curl https://install.meteor.com > install_meteor.sh
chmod u+x install_meteor.sh
./install_meteor.sh

Bây giờ bạn có thể tạo một dự án mới.


Tạo một dự án mới

Lệnh meteor tự động hóa quá trình tạo ra một dự án mới với tất cả những gì Meteor cần để vận hành. Gõ các lệnh được hiển thị trong Liệt kê 2 để tạo một dự án mới với tên realtime_links.

Liệt kê 2. Tạo dự án Meteor của bạn
meteor realtime_links
cd realtime_links

Meteor tạo ra một thư mục chứa một tệp HTML, một tệp JavaScript, và một tệp CSS (Cascading Style Sheets). Tệp cuối cùng là một tệp CSS chuẩn, nhưng hai tệp đầu tiên thì đáng để bàn tới. Bạn có thể tải về phiên bản đầy đủ của cả hai tệp realtime_links.html và realtime_links.js từ mục Tải về.


Tệp realtime_links.html

Liệt kê 3 hiển thị phần header và body trong tệp The realtime_links.html.

Liệt kê 3. Phần header và body trong tệp realtime_links.html
<head>
<title>Realtime Links Demo</title>
</head>

<body>
  {{> header }}
  {{> link_list }}
  {{> add_new_link }}
</body>

Như các bạn thấy, bắt đầu một khuôn mẫu HTML rất đơn giản. Bạn không cần phải lo lắng về các thẻ BODY, DOCTYPE hay thậm chí là các tệp JavaScript và CSS. Meteor giải quyết tất cả những việc đó cho bạn. Để biết thêm thông tin về gói JavaScript và CSS của Meteor, hãy xem phần Tài nguyên để tìm liên kết đến trang web của Meteor.

Cú pháp {{> có nghĩa là "biểu diễn khuôn mẫu này". Như bạn có thể thấy, tệp realtime_links.html biểu diễn ba khuôn mẫu:

  • header là một tiêu đề đơn giản hiển thị số lượng các liên kết trong cơ sở dữ liệu.
  • link_list hiển thị danh sách liên kết và bình chọn liên quan đến chúng.
  • add_new_link là một mẫu nhập để bạn thêm vào các liên kết mới.

Liệt kê 4 hiển thị khuôn mẫu header

Liệt kê 4. Khuôn mẫu header của tệp realtime_links.html
<template name="header">


<h1>The Link Collection</h1>

	<p>We currently have {{collection_size}} links.</p>

</template>

Khuôn mẫu header đơn giản là biểu diễn một thẻ h1 và một đoạn mô tả ngắn về kích thước của bộ sưu tập. Phương thức collection_size được định nghĩa trong tệp JavaScript, realtime_links.js (chúng sẽ thảo luận về tệp này nhiều hơn trong phần sau). Meteor tự động nắm bắt được những phần dữ liệu được suy ra từ khuôn mẫu. Vì thế, khi kích thước của bộ sưu tập được cập nhật, khuôn mẫu header sẽ tự động cập nhật lại.

Chú ý rằng cú pháp {{ ... } được sử dụng ở đây tương tự như <%= ... %> trong Ruby on Rails hoặc <?= ... ?> trong PHP. Nó có thể sinh ra đoạn mã tùy ý, vì vậy bạn có thể chèn thêm bất kỳ biểu thức nào hữu ích vào bên trong đó để thêm sinh động.

Liệt kê 5 hiển thị khuôn mẫu link_list.

Liệt kê 5. Khuôn mẫu link_list của realtime_links.html
<template name=
"link_list">

  <ul>

    {{#each links }}

      <li>  {{> link_detail }} </li>

    {{/each }}

  </ul>

</template>

Như bạn có thể thấy, đoạn mã trong Liệt kê 5 là danh sách các liên kết. Những phương thức links trong tệp JavaScript realtime_links.js tạo ra danh sách này. Khuôn mẫu link_detail biểu diễn mỗi liên kết. Chú ý là bạn không cần phải truyền vào bất kỳ đối số nào bởi vì vòng lặp #each của Handlebars sẽ thiết lập theo ngữ cảnh hiện tại cho mỗi lần lặp là một đối tượng hiện tại. Nói cách khác, các phương thức cục bộ của khuôn mẫu link_detail được làm rõ như các phương thức của mỗi đối tượng liên kết.

Liệt kê 6 hiển thị khuôn mẫulink_detail, kiểm soát các dữ liệu hiển thị cho mỗi liên kết riêng lẻ.

Liệt kê 6. Khuôn mẫu link_detail của realtime_links.html
<template name="link_detail">


<div id="link-{{id}}">

    <h1>{{url}}</h1>

    <p><strong>Stats:</strong> up: {{thumbs_up}} down: {{thumbs_down}} 
net score: {{score}}</p>


<input type="button" value="Thumbs Up" 
 class="thumbs_up" url="{{url}}" />
    <input type="button" value="Thumbs Down" 
class="thumbs_down" url="{{url}}" />


</div>

</template>

Phần tử h1 đơn giản chỉ hiển thị URL của liên kết hiện tại. Và sau đó sẽ có một danh sách ngắn gọn bao gồm số lần mà một liên kết đã được bình chọn ủng hộ, số lần mà nó được bình chọn là không ủng hộ và điểm số của liên kết đó, chính là sự khác nhau giữa hai giá trị. Cuối cùng là có hai nút bấm: một nút là hình ngón tay cái quay lên là được bình chọn ủng hộ và một nút là hình ngón tay cái quay xuống là không được ủng hộ. Các tệp JavaScript xác định hành vi cho các nút này nhưng có hơn một khuôn mẫu để kiểm tra trước khi thu thập thông tin của chúng.

Liệt kê 7 hiển thị khuôn mẫu add_new_link.

Liệt kê 7. Khuôn mẫu add_new_link của realtime_links.html
<template name="add_new_link">

  <div id="new_link_form">

    URL: <input id="url">

<input type="button" value="Click" id="add_url" />

  </div>

</template>

Khuôn mẫu này chỉ đơn giản là một trường nhập dữ liệu văn bản và một nút kết hợp với nhau tạo thành giao diện để thêm URL mới vào danh sách của bạn.


Tệp realtime_links.js

Đoạn mã trong tệp JavaScript realtime_links.js điều khiển truy cập dữ liệu và các lời gọi lại (callbacks) từ chương trình, cả trên máy khách và máy chủ. Câu lệnh if (Meteor.is_client) đánh dấu bên phía máy khách (client), và câu lệnh if (Meteor.is_server) đánh dấu bên phía máy chủ (server). Meteor cung cấp cách để bảo vệ các đoạn mã nhạy cảm để máy khách nào mà có "ý đồ xấu" thì sẽ không thể xem được mã nguồn. Xem các liên kết đến tài liệu Meteor trong phần Tài nguyên để biết thêm chi tiết.

Liệt kê 8 hiển thị các hàm trợ giúp của danh sách header và liên kết.

Liệt kê 8. Các hàm trợ giúp của danh sách header và liên kết
Template.header.collection_size = function () {
return Links.find({}).count();
	};


	Template.link_list.links = function () {
return Links.find({}, {sort : {score: -1} });
	};

Khuôn mẫu header sử dụng các hàm trợ giúp đầu tiên trong danh sách, các hàm này đơn giản trả về kích cỡ của tập các links. Khuôn mẫu link_list sử dụng hàm trợ giúp thứ hai, trả về tất cả các liên kết được sắp xếp từ điểm cao nhất đến điểm thấp nhất.

Liệt kê 9 có hai sự kiện gọi lại cho khuôn mẫu link_detail.

Liệt kê 9. Sự kiện gọi lại của link_detail
	Template.link_detail.events = 
{

'click input.thumbs_up' : function () {
Meteor.call('vote', this.url, 'thumbs_up');
},

  'click input.thumbs_down' : function 
() {Meteor.call('vote', this.url, 'thumbs_down');}

	};

Mỗi sự kiện gọi lại sẽ xử lý một sự kiện nhấn bình chọn ủng hộ hay không ủng hộ. Trong cả hai trường hợp, họ sẽ sử dụng Meteor.call ở máy khách (client) để tạo nên một hàm gọi đến máy chủ (server). Như các bạn cũng thấy, thực hiện cuộc gọi từ máy khách (client) đến máy chủ (server) là dễ dàng. Ví dụ, tính tuần tự hóa được xử lý tự động.

Liệt kê 10 hiển thị các sự kiện gọi lại cho mẫu nhập (form) nơi mà người dùng có thể thêm các liên kết mới.

Liệt kê 10. Sự kiện gọi lại cho mẫu nhập (form) thêm liên kết mới
  Template.add_new_link.events = {

    'click input#add_url' : 
dfunction () {

var new_url = $('#url').val();

      var url_row = Links.findOne( {url:new_url} );

      if(!url_row){

Links.insert( { url : new_url,
score: 0,
thumbs_up: 0,

thumbs_down: 0 });
      }
Meteor.call('vote', url, 'thumbs_up');

    }
  };

Đầu tiên, phải tìm cách xác định vị trí một đối tượng liên kết hiện có với các URL được yêu cầu. Nếu như tìm thấy, nó sẽ đếm số yêu cầu như một phiếu bình chọn cho đối tượng liên kết hiện có. Nếu không tìm thấy nó sẽ tạo ra một đối tượng liên kết mới và tạo ra một bình chọn thumbs_up (ủng hộ) cho đối tượng mới.

Đoạn mã này minh họa những lợi ích và hạn chế của Meteor như một công nghệ đột phá nhưng vẫn chưa được áp dụng vào thực tế sử dụng. Như bạn thấy, bên máy khách có thể gọi hàm insert trên tập hợp links. Trong khi điều này rất hữu ích cho các nhà phát triển, thì nó hoàn toàn có vấn đề ở góc độ an ninh, bảo mật. Rất may mắn là các nhà phát triển tích cực làm việc dựa trên auth của các đoạn mã giúp thực hiện các tính năng xác thực mạnh mẽ trong khi vẫn giữ được tính linh hoạt, điều này chính là sức hấp dẫn của Meteor.

Thêm vào đó, nhận thấy rằng Meteor không triển khai hết tất cả các tính năng của MongoDB. Ví dụ, Meteor không hỗ trợ chèn MongoDB mà chèn mới dữ liệu hoặc sửa đổi dữ liệu cũ. Nếu Meteor có hỗ trợ chèn và cập nhật (upsert) thì bạn có thể viết các hàm như hiển thị trong Liệt kê 11.

Liệt kê 11. Định nghĩa sự kiện gọi lại của mẫu nhập (form) thêm mới liên kết với upsert
  Template.add_new_link.events = {

    'click input#add_url' : function () {

      var new_url = $('#url').val();

       Links.update( { url : new_url}, 
                     { $set: {url : new_url}, 
                       $inc: { votes : 1 } } , true );


    }
  };

Như bạn thấy, đoạn mã viết ngắn hơn khi sử dụng upsert. Nó có thể nhanh hơn bởi vì nó chỉ cần đi một vòng đến máy chủ. Hy vọng rằng, Meteor sẽ sớm hỗ trợ cho upsert và các tính năng mới khác.

Đoạn mã trong Liệt kê 12 chạy trên server. Đây là một phương thức đơn có thể được gọi bởi mã phía máy khách. Phương thức vote, này cho phép bên máy khách có thể bình chọn thumbs_up (ủng hộ) hay thumbs_down (không ủng hộ) trên địa chỉ URL cụ thể. Nó sử dụng toán tử $inc của Mongo để tăng lượt bình chọn thích hợp. Nó cũng tăng hay giảm số điểm tổng khi cần thiết. Phương thức Meteor.startup cho phép đoạn mã chỉ được chạy khi máy chủ khởi động. Hàm Meteor.methods sau đó định nghĩa các hàm được gọi trên máy khách sử dụng phương thức Meteor.call, như hiển thị trong Liệt kê 9.

Liệt kê 12. Đoạn mã cho phương thức vote bên phía máy chủ
if (Meteor.is_server) {
    Meteor.startup(function () {
      Meteor.methods({
        vote: function (url, field){

new_obj = { $inc: { } };

 if(field =='thumbs_up'){
new_obj['$inc']['thumbs_up'] = 1;
 new_obj['$inc']['score'] = 1;
 }else{
new_obj['$inc']['thumbs_down'] = 1;
 new_obj['$inc']['score'] = -1;
                }

                Links.update( { url : url}, new_obj );

              }
      });
    });
}

Như Liệt kê 10, bạn có thể chạy đoạn mã trong Liệt kê 12 trên máy khách. Tuy nhiên, với mục đích là minh họa, nó được chạy trên máy chủ. Như tiến trình mô hình bảo mật của Meteor, nó giống như một đoạn mã nhạy cảm sẽ được phát triển bên phía máy chủ với các hàm như trong Liệt kê này.


Xem ứng dụng của bạn hoạt động

Đến bước này, bạn có thể khởi chạy ứng dụng Meteor của bạn, như trong Liệt kê 13, và xem nó hoạt động.

Liệt kê 13. Khởi động hệ thống của bạn
meteor

Sau khi khởi động, Meteor chạy trên cổng 3000. Hãy mở một trình duyệt web, và truy cập vào địa chỉ http://localhost:3000/.

Nếu bạn nhập một URL vào phần Add a URL và kích Add, bạn sẽ thấy một URL hiển thị với điểm số là one. Bạn có thể kích vào nút Thumbs Up hoặc Thumbs Down để bỏ phiếu hoặc phản đối URL. Điều này diễn ra theo thời gian thực và không cần làm mới (refresh) lại trang. Nếu bạn mở một trình duyệt mới, bạn có thể làm giống như vậy trong cửa sổ mới và các thay đổi sẽ được thể hiện ngay trong cửa sổ đầu tiên.

Khi bạn thêm nhiều URL, bạn có thể thấy một cái với điểm số cao nhất—điểm số được định nghĩa là số phiếu ủng hộ trừ đi số phiếu không ủng hộ—hiển thị ở trên cùng. Như bạn có thể bỏ phiếu ủng hộ hoặc không ủng hộ, URL di chuyển lên hoặc xuống trong danh sách theo như sự thay đổi thứ hạng của nó. Điều này diễn ra theo thời gian thực với nhiều người dùng trên nhiều trình duyệt, tất cả cùng nhận một dữ liệu giống nhau, như là các thao tác bỏ phiếu.


Kết luận

Meteor là một khung cộng tác web tiên tiến chứa nhiều khái niệm thú vị. Nó hỗ trợ cho dữ liệu thời gian thực, vừa thu hút vừa quan trọng, đặc biệt là so với những công nghệ hỗ trợ thời gian thực khác thì Meteor một lựa chọn tốt nhất. Việc tương tác thời gian thực sẽ trở nên quan trọng trong các trang web tương lai, khả năng của Meteor khiến bạn dễ dàng và nhanh chóng làm việc với các tập dữ liệu phức tạp theo thời gian thực sẽ tiếp tục trở nên quan trọng hơn.


Tải về

Mô tảTênKích thước
Mã nguồn ví dụ mẫu trong bài nàyrealtime_links.zip2KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=950550
ArticleTitle=Phát triển trang web thời gian thực dễ dàng với Meteor
publish-date=10292013